Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(core): handle no payload methods Co-authored-by: David Müller <[email protected]> fix(core): extract AsyncMessage#description Co-authored-by: David Müller <[email protected]> feat(core): use fqn in for schema name Co-authored-by: David Müller <[email protected]> refactor(core): split test for PayloadClassExtractor and TypeToClassConverter Co-authored-by: Timon Back <[email protected]> test(kafka): remove unused use-fqn setting Co-authored-by: David Müller <[email protected]> test(kafka): update asyncapi.json Co-authored-by: David Müller <[email protected]> refactor(core): extract TypeToClassConverter Co-authored-by: David Müller <[email protected]> refactor(core): replace pair of resolved schema name and schema object with a specific record Co-authored-by: Timon Back <[email protected]> feat(core): add NoPayloadUsedConsumer Co-authored-by: David Müller <[email protected]> refactor(core): update AsyncHeadersBuilder (wip) Co-authored-by: David Müller <[email protected]> feat(core): Use new PayloadService (wip) Co-authored-by: David Müller <[email protected]> refactor(core): Check description in Schema annotation in DefaultComponentsService test(core): Add PayloadServiceTest refactor(core): Give PayloadService a name feat(core): Add PayloadNotUsed Schema Co-authored-by: Timon Back <[email protected]> refactor(core): PayloadClassExtractor returns optional instead of throwing an exception Co-authored-by: Timon Back <[email protected]> diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java index 9ccf6e1c..e6302005 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java @@ -7,10 +7,12 @@ import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.ToString; @Getter @JsonSerialize(using = MessagePayloadSerializer.class) @EqualsAndHashCode +@ToString public class MessagePayload { private MultiFormatSchema multiFormatSchema; private SchemaObject schema; diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java index b938b4d4..bc6b16b9 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java @@ -9,6 +9,7 @@ import lombok.NoArgsConstructor; import lombok.ToString; @EqualsAndHashCode +@ToString @NoArgsConstructor @AllArgsConstructor public class MessageReference implements Message, Reference { diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaObject.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaObject.java index 710a3ed0..497fb78e 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaObject.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaObject.java @@ -10,6 +10,7 @@ import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.ToString; import java.math.BigDecimal; import java.util.List; @@ -31,6 +32,7 @@ import java.util.Map; @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) +@ToString public class SchemaObject extends ExtendableObject implements Schema { /** * Adds support for polymorphism. The discriminator is the schema property name that is used to differentiate diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaReference.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaReference.java index 2384a153..848c27fb 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaReference.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaReference.java @@ -9,6 +9,7 @@ import lombok.NoArgsConstructor; import lombok.ToString; @EqualsAndHashCode +@ToString @NoArgsConstructor @AllArgsConstructor public class SchemaReference implements Schema, Reference { diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java index 9c982b3d..f5132257 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java @@ -12,6 +12,8 @@ public interface ComponentsService { Map<String, SchemaObject> getSchemas(); + SchemaObject resolveSchema(String schemaName); + String registerSchema(SchemaObject headers); String registerSchema(Class<?> type); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java index 59caf4e5..f2e3104c 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java @@ -14,6 +14,7 @@ import io.swagger.v3.core.jackson.TypeNameResolver; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; +import jakarta.annotation.Nullable; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -60,6 +61,15 @@ public class DefaultComponentsService implements ComponentsService { .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } + @Override + @Nullable + public SchemaObject resolveSchema(String schemaName) { + if (schemas.containsKey(schemaName)) { + return swaggerSchemaUtil.mapSchema(schemas.get(schemaName)); + } + return null; + } + @Override public String registerSchema(SchemaObject headers) { log.debug("Registering schema for {}", headers.getTitle()); @@ -81,6 +91,7 @@ public class DefaultComponentsService implements ComponentsService { @Override public String registerSchema(Class<?> type) { + // FIXME: Move this to the new HeadersService return this.registerSchema(type, properties.getDocket().getDefaultContentType()); } @@ -90,13 +101,13 @@ public class DefaultComponentsService implements ComponentsService { String actualContentType = StringUtils.isBlank(contentType) ? properties.getDocket().getDefaultContentType() : contentType; - Map<String, Schema> schemas = new LinkedHashMap<>(runWithFqnSetting((unused) -> converter.readAll(type))); + Map<String, Schema> newSchemas = new LinkedHashMap<>(runWithFqnSetting((unused) -> converter.readAll(type))); - String schemaName = getSchemaName(type, schemas); + String schemaName = getSchemaName(type, newSchemas); - preProcessSchemas(schemas, schemaName, type); - schemas.forEach(this.schemas::putIfAbsent); - schemas.values().forEach(schema -> postProcessSchema(schema, actualContentType)); + preProcessSchemas(newSchemas, schemaName, type); + newSchemas.forEach(this.schemas::putIfAbsent); + newSchemas.values().forEach(schema -> postProcessSchema(schema, actualContentType)); return schemaName; } @@ -130,11 +141,22 @@ public class DefaultComponentsService implements ComponentsService { return new ArrayList<>(resolvedPayloadModelName).get(0); } - return type.getSimpleName(); + return getNameFromClass(type); } private void preProcessSchemas(Map<String, Schema> schemas, String schemaName, Class<?> type) { processAsyncApiPayloadAnnotation(schemas, schemaName, type); + processSchemaAnnotation(schemas, schemaName, type); + } + + private void processSchemaAnnotation(Map<String, Schema> schemas, String schemaName, Class<?> type) { + Schema schemaForType = schemas.get(schemaName); + if (schemaForType != null) { + var schemaAnnotation = type.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + if (schemaAnnotation != null) { + schemaForType.setDescription(schemaAnnotation.description()); + } + } } private void processAsyncApiPayloadAnnotation(Map<String, Schema> schemas, String schemaName, Class<?> type) { @@ -161,9 +183,9 @@ public class DefaultComponentsService implements ComponentsService { } private String registerString() { - String schemaName = "String"; + String schemaName = getNameFromClass(String.class); StringSchema schema = new StringSchema(); - schema.setName(String.class.getName()); + schema.setName(schemaName); this.schemas.put(schemaName, schema); postProcessSchema(schema, DEFAULT_CONTENT_TYPE); @@ -181,6 +203,13 @@ public class DefaultComponentsService implements ComponentsService { return result; } + private String getNameFromClass(Class<?> type) { + if (properties.isUseFqn()) { + return type.getName(); + } + return type.getSimpleName(); + } + private void postProcessSchema(Schema schema, String contentType) { for (SchemasPostProcessor processor : schemaPostProcessors) { processor.process(schema, schemas, contentType); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersBuilder.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersBuilder.java index 195fcb13..0496125f 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersBuilder.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersBuilder.java @@ -2,7 +2,8 @@ package io.github.springwolf.core.asyncapi.components.headers; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; public interface AsyncHeadersBuilder { - SchemaObject buildHeaders(Class<?> payloadType); + SchemaObject buildHeaders(NamedSchemaObject payloadSchema); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotDocumented.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotDocumented.java index b1548c4e..77b177bf 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotDocumented.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotDocumented.java @@ -2,6 +2,7 @@ package io.github.springwolf.core.asyncapi.components.headers; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; import java.util.List; import java.util.Map; @@ -22,7 +23,7 @@ public class AsyncHeadersNotDocumented implements AsyncHeadersBuilder { } @Override - public SchemaObject buildHeaders(Class<?> payloadType) { + public SchemaObject buildHeaders(NamedSchemaObject payloadSchema) { return NOT_DOCUMENTED; } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotUsed.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotUsed.java index 19ffed26..8b026f07 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotUsed.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/headers/AsyncHeadersNotUsed.java @@ -2,6 +2,7 @@ package io.github.springwolf.core.asyncapi.components.headers; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; import java.util.List; import java.util.Map; @@ -21,7 +22,7 @@ public class AsyncHeadersNotUsed implements AsyncHeadersBuilder { } @Override - public SchemaObject buildHeaders(Class<?> payloadType) { + public SchemaObject buildHeaders(NamedSchemaObject payloadSchema) { return NOT_USED; } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java index 253e1c7c..7c28ddab 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java @@ -15,6 +15,7 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.operations.Operation import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AsyncAnnotationUtil; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import lombok.extern.slf4j.Slf4j; @@ -36,11 +37,13 @@ public class AsyncAnnotationChannelsScanner<A extends Annotation> extends AsyncA ComponentsService componentsService, AsyncApiDocketService asyncApiDocketService, PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, List<OperationBindingProcessor> operationBindingProcessors, List<MessageBindingProcessor> messageBindingProcessors) { super( asyncAnnotationProvider, payloadClassExtractor, + payloadService, componentsService, operationBindingProcessors, messageBindingProcessors); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java index d86fff29..22d88226 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java @@ -8,7 +8,7 @@ import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeadersBuilder; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.ClassLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import lombok.extern.slf4j.Slf4j; @@ -30,14 +30,14 @@ public class SpringAnnotationClassLevelChannelsScanner< Class<MethodAnnotation> methodAnnotationClass, BindingFactory<ClassAnnotation> bindingFactory, AsyncHeadersBuilder asyncHeadersBuilder, - PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, ComponentsService componentsService) { super( classAnnotationClass, methodAnnotationClass, bindingFactory, asyncHeadersBuilder, - payloadClassExtractor, + payloadService, componentsService); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java index c2942147..2321fa21 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java @@ -9,7 +9,8 @@ import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeadersBuilder; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.MethodLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import lombok.extern.slf4j.Slf4j; @@ -25,17 +26,17 @@ public class SpringAnnotationMethodLevelChannelsScanner<MethodAnnotation extends extends MethodLevelAnnotationScanner<MethodAnnotation> implements SpringAnnotationChannelsScannerDelegator { private final Class<MethodAnnotation> methodAnnotationClass; - private final PayloadClassExtractor payloadClassExtractor; + private final PayloadService payloadService; public SpringAnnotationMethodLevelChannelsScanner( Class<MethodAnnotation> methodAnnotationClass, BindingFactory<MethodAnnotation> bindingFactory, AsyncHeadersBuilder asyncHeadersBuilder, - PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, ComponentsService componentsService) { super(bindingFactory, asyncHeadersBuilder, componentsService); this.methodAnnotationClass = methodAnnotationClass; - this.payloadClassExtractor = payloadClassExtractor; + this.payloadService = payloadService; } @Override @@ -56,16 +57,15 @@ public class SpringAnnotationMethodLevelChannelsScanner<MethodAnnotation extends MethodAnnotation annotation = AnnotationScannerUtil.findAnnotationOrThrow(methodAnnotationClass, method); + NamedSchemaObject payloadSchema = payloadService.extractSchema(method); + ChannelObject channelItem = buildChannelItem(annotation, payloadSchema); + String channelName = bindingFactory.getChannelName(annotation); - Class<?> payload = payloadClassExtractor.extractFrom(method); - - ChannelObject channelItem = buildChannelItem(annotation, payload); - return Map.entry(channelName, channelItem); } - private ChannelObject buildChannelItem(MethodAnnotation annotation, Class<?> payloadType) { - MessageObject message = buildMessage(annotation, payloadType); + private ChannelObject buildChannelItem(MethodAnnotation annotation, NamedSchemaObject payloadSchema) { + MessageObject message = buildMessage(annotation, payloadSchema); return buildChannelItem(annotation, message); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java index 0dbba50d..48884d26 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java @@ -17,7 +17,9 @@ import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import io.github.springwolf.core.asyncapi.scanners.common.utils.AsyncAnnotationUtil; import io.github.springwolf.core.asyncapi.scanners.common.utils.TextUtils; @@ -42,6 +44,7 @@ public abstract class AsyncAnnotationScanner<A extends Annotation> implements Em protected final AsyncAnnotationProvider<A> asyncAnnotationProvider; protected final PayloadClassExtractor payloadClassExtractor; + protected final PayloadService payloadService; protected final ComponentsService componentsService; protected final List<OperationBindingProcessor> operationBindingProcessors; protected final List<MessageBindingProcessor> messageBindingProcessors; @@ -89,30 +92,33 @@ public abstract class AsyncAnnotationScanner<A extends Annotation> implements Em } protected MessageObject buildMessage(AsyncOperation operationData, Method method) { - Class<?> payloadType = operationData.payloadType() != Object.class - ? operationData.payloadType() - : payloadClassExtractor.extractFrom(method); + NamedSchemaObject payloadSchema = payloadService.extractSchema(operationData, method); - String modelName = this.componentsService.registerSchema( - payloadType, operationData.message().contentType()); - SchemaObject asyncHeaders = AsyncAnnotationUtil.getAsyncHeaders(operationData, resolver); - String headerModelName = this.componentsService.registerSchema(asyncHeaders); - var headers = MessageHeaders.of(MessageReference.toSchema(headerModelName)); - - var schema = payloadType.getAnnotation(Schema.class); - String description = schema != null ? schema.description() : null; + // TODO: move block to own HeaderService + SchemaObject headerSchema = AsyncAnnotationUtil.getAsyncHeaders(operationData, resolver); + String headerSchemaName = this.componentsService.registerSchema(headerSchema); + var headers = MessageHeaders.of(MessageReference.toSchema(headerSchemaName)); Map<String, MessageBinding> messageBinding = AsyncAnnotationUtil.processMessageBindingFromAnnotation(method, messageBindingProcessors); var messagePayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(modelName)) + .schema(SchemaReference.fromSchema(payloadSchema.name())) .build()); + String description = operationData.message().description(); + if (!StringUtils.hasText(description)) { + description = payloadSchema.schema().getDescription(); + } + if (StringUtils.hasText(description)) { + description = this.resolver.resolveStringValue(description); + description = TextUtils.trimIndent(description); + } + var builder = MessageObject.builder() - .messageId(payloadType.getName()) - .name(payloadType.getName()) - .title(payloadType.getSimpleName()) + .messageId(payloadSchema.name()) + .name(payloadSchema.name()) + .title(payloadSchema.schema().getTitle()) .description(description) .payload(messagePayload) .headers(headers) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java index f814e939..8a7f6507 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java @@ -11,7 +11,8 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeadersBuilder; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationClassLevelOperationsScanner; import lombok.RequiredArgsConstructor; @@ -37,7 +38,7 @@ public abstract class ClassLevelAnnotationScanner< protected final Class<MethodAnnotation> methodAnnotationClass; protected final BindingFactory<ClassAnnotation> bindingFactory; protected final AsyncHeadersBuilder asyncHeadersBuilder; - protected final PayloadClassExtractor payloadClassExtractor; + protected final PayloadService payloadService; protected final ComponentsService componentsService; protected enum MessageType { @@ -67,8 +68,8 @@ public abstract class ClassLevelAnnotationScanner< SpringAnnotationClassLevelOperationsScanner.MessageType messageType) { Set<MessageObject> messages = methods.stream() .map((Method method) -> { - Class<?> payloadType = payloadClassExtractor.extractFrom(method); - return buildMessage(classAnnotation, payloadType); + NamedSchemaObject payloadSchema = payloadService.extractSchema(method); + return buildMessage(classAnnotation, payloadSchema); }) .collect(toSet()); @@ -79,18 +80,19 @@ public abstract class ClassLevelAnnotationScanner< return toMessagesMap(messages); } - protected MessageObject buildMessage(ClassAnnotation classAnnotation, Class<?> payloadType) { + protected MessageObject buildMessage(ClassAnnotation classAnnotation, NamedSchemaObject payloadSchema) { Map<String, MessageBinding> messageBinding = bindingFactory.buildMessageBinding(classAnnotation); - String modelName = componentsService.registerSchema(payloadType); - String headerModelName = componentsService.registerSchema(asyncHeadersBuilder.buildHeaders(payloadType)); + + String headerModelName = componentsService.registerSchema(asyncHeadersBuilder.buildHeaders(payloadSchema)); + MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(modelName)) + .schema(SchemaReference.fromSchema(payloadSchema.name())) .build()); MessageObject message = MessageObject.builder() - .messageId(payloadType.getName()) - .name(payloadType.getName()) - .title(payloadType.getSimpleName()) + .messageId(payloadSchema.name()) + .name(payloadSchema.name()) + .title(payloadSchema.schema().getTitle()) .description(null) .payload(payload) .headers(MessageHeaders.of(MessageReference.toSchema(headerModelName))) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java index 1d548122..72f5e823 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java @@ -11,6 +11,7 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeadersBuilder; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -25,18 +26,20 @@ public abstract class MethodLevelAnnotationScanner<MethodAnnotation extends Anno protected final AsyncHeadersBuilder asyncHeadersBuilder; protected final ComponentsService componentsService; - protected MessageObject buildMessage(MethodAnnotation annotation, Class<?> payloadType) { + protected MessageObject buildMessage(MethodAnnotation annotation, NamedSchemaObject payloadSchema) { Map<String, MessageBinding> messageBinding = bindingFactory.buildMessageBinding(annotation); - String modelName = componentsService.registerSchema(payloadType); - String headerModelName = componentsService.registerSchema(asyncHeadersBuilder.buildHeaders(payloadType)); + + // TODO: move block to own HeaderService + String headerModelName = componentsService.registerSchema(asyncHeadersBuilder.buildHeaders(payloadSchema)); + MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(modelName)) + .schema(SchemaReference.fromSchema(payloadSchema.name())) .build()); MessageObject message = MessageObject.builder() - .messageId(payloadType.getName()) - .name(payloadType.getName()) - .title(payloadType.getSimpleName()) + .messageId(payloadSchema.name()) + .name(payloadSchema.name()) + .title(payloadSchema.schema().getTitle()) .description(null) .payload(payload) .headers(MessageHeaders.of(MessageReference.toSchema(headerModelName))) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/NamedSchemaObject.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/NamedSchemaObject.java new file mode 100644 index 00000000..9509becf --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/NamedSchemaObject.java @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.payload; + +import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; + +/** + * Encapsulates the resolved name for the contained schema. + * @param name The fully qualified name or the simple name of the schema. + * @param schema The SchemaObject. + */ +public record NamedSchemaObject(String name, SchemaObject schema) {} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadClassExtractor.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadClassExtractor.java index 0d19c5e6..9e80ef74 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadClassExtractor.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadClassExtractor.java @@ -1,52 +1,34 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload; -import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.handler.annotation.Payload; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.util.Arrays; -import java.util.Map; +import java.util.Optional; +@RequiredArgsConstructor @Slf4j public class PayloadClassExtractor { private final TypeToClassConverter typeToClassConverter; - public PayloadClassExtractor(SpringwolfConfigProperties properties) { - Map<String, Integer> extractableClasses = Map.of(); - if (properties.getPayload() != null) { - extractableClasses = properties.getPayload().getExtractableClasses(); - } - typeToClassConverter = new TypeToClassConverter(extractableClasses); - } - - public Class<?> extractFrom(Method method) { + public Optional<Class<?>> extractFrom(Method method) { String methodName = String.format("%s::%s", method.getDeclaringClass().getSimpleName(), method.getName()); log.debug("Finding payload type for {}", methodName); - int parameterPayloadIndex = - getPayloadParameterIndex(method.getParameterTypes(), method.getParameterAnnotations(), methodName); - - return typeToClassConverter.extractClass(method.getGenericParameterTypes()[parameterPayloadIndex]); + return getPayloadParameterIndex(method.getParameterTypes(), method.getParameterAnnotations(), methodName) + .map((parameterPayloadIndex) -> + typeToClassConverter.extractClass(method.getGenericParameterTypes()[parameterPayloadIndex])); } - public Class<?> typeToClass(Type type) { - return typeToClassConverter.extractClass(type); - } - - private int getPayloadParameterIndex( + private Optional<Integer> getPayloadParameterIndex( Class<?>[] parameterClasses, Annotation[][] parameterAnnotations, String methodName) { - switch (parameterClasses.length) { - case 0 -> throw new IllegalArgumentException( - "Payload cannot be detected. Method must not have 0 parameters: " + methodName); - case 1 -> { - return 0; - } + return switch (parameterClasses.length) { + case 0 -> Optional.empty(); + case 1 -> Optional.of(0); default -> { int payloadAnnotatedParameterIndex = getPayloadAnnotatedParameterIndex(parameterAnnotations); if (payloadAnnotatedParameterIndex == -1) { @@ -57,9 +39,9 @@ public class PayloadClassExtractor { throw new IllegalArgumentException(msg); } - return payloadAnnotatedParameterIndex; + yield Optional.of(payloadAnnotatedParameterIndex); } - } + }; } private int getPayloadAnnotatedParameterIndex(Annotation[][] parameterAnnotations) { @@ -74,58 +56,4 @@ public class PayloadClassExtractor { return -1; } - - @RequiredArgsConstructor - private static class TypeToClassConverter { - - private final Map<String, Integer> extractableClassToArgumentIndex; - - private Class<?> extractClass(Type parameterType) { - try { - if (parameterType instanceof ParameterizedType) { - Type rawParameterType = ((ParameterizedType) parameterType).getRawType(); - String rawParameterTypeName = rawParameterType.getTypeName(); - - Class<?> actualPayloadClass = - extractActualGenericClass((ParameterizedType) parameterType, rawParameterTypeName); - if (actualPayloadClass != Void.class) { - return actualPayloadClass; - } - - // nested generic class - fallback to most outer container - return Class.forName(rawParameterTypeName); - } - - // no generics used - just a normal type - return Class.forName(parameterType.getTypeName()); - } catch (Exception ex) { - log.info("Unable to extract generic data type of {}", parameterType, ex); - } - return Void.class; - } - - private Class<?> extractActualGenericClass(ParameterizedType parameterType, String rawParameterTypeName) { - Type type = parameterType; - String typeName = rawParameterTypeName; - - while (type instanceof ParameterizedType && extractableClassToArgumentIndex.containsKey(typeName)) { - Integer index = extractableClassToArgumentIndex.get(rawParameterTypeName); - - type = ((ParameterizedType) type).getActualTypeArguments()[index]; - - typeName = type.getTypeName(); - if (type instanceof ParameterizedType) { - typeName = ((ParameterizedType) type).getRawType().getTypeName(); - } - } - - try { - return Class.forName(typeName); - } catch (ClassNotFoundException ex) { - log.debug("Unable to find class for type {}", typeName, ex); - } - - return Void.class; - } - } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadService.java new file mode 100644 index 00000000..69342a90 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadService.java @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.payload; + +import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +public class PayloadService { + private final PayloadClassExtractor payloadClassExtractor; + private final ComponentsService componentsService; + private final SpringwolfConfigProperties properties; + + private static final String PAYLOAD_NOT_USED_KEY = "PayloadNotUsed"; + static final NamedSchemaObject PAYLOAD_NOT_USED = new NamedSchemaObject( + PAYLOAD_NOT_USED_KEY, + SchemaObject.builder() + .title(PAYLOAD_NOT_USED_KEY) + .description("No payload specified") + .properties(Map.of()) + .build()); + + public NamedSchemaObject extractSchema(Method method) { + Optional<Class<?>> payloadType = payloadClassExtractor.extractFrom(method); + + String contentType = properties.getDocket().getDefaultContentType(); + return payloadType.map((type) -> buildSchema(contentType, type)).orElseGet(this::useUnusedPayload); + } + + public NamedSchemaObject extractSchema(AsyncOperation operationData, Method method) { + Optional<Class<?>> payloadType = operationData.payloadType() != Object.class + ? Optional.of(operationData.payloadType()) + : payloadClassExtractor.extractFrom(method); + + String contentType = operationData.message().contentType(); + return payloadType.map((type) -> buildSchema(contentType, type)).orElseGet(this::useUnusedPayload); + } + + private NamedSchemaObject buildSchema(String contentType, Class<?> payloadType) { + String componentsSchemaName = this.componentsService.registerSchema(payloadType, contentType); + + SchemaObject schema = componentsService.resolveSchema(componentsSchemaName); + schema.setTitle(payloadType.getSimpleName()); + + return new NamedSchemaObject(componentsSchemaName, schema); + } + + private NamedSchemaObject useUnusedPayload() { + this.componentsService.registerSchema(PAYLOAD_NOT_USED.schema()); + return PAYLOAD_NOT_USED; + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/TypeToClassConverter.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/TypeToClassConverter.java new file mode 100644 index 00000000..c55f8254 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/TypeToClassConverter.java @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.payload; + +import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Map; + +@Slf4j +public class TypeToClassConverter { + + private final Map<String, Integer> extractableClassToArgumentIndex; + + public TypeToClassConverter(SpringwolfConfigProperties properties) { + if (properties.getPayload() != null) { + extractableClassToArgumentIndex = properties.getPayload().getExtractableClasses(); + } else { + extractableClassToArgumentIndex = Map.of(); + } + } + + public Class<?> extractClass(Type parameterType) { + try { + if (parameterType instanceof ParameterizedType) { + Type rawParameterType = ((ParameterizedType) parameterType).getRawType(); + String rawParameterTypeName = rawParameterType.getTypeName(); + + Class<?> actualPayloadClass = + extractActualGenericClass((ParameterizedType) parameterType, rawParameterTypeName); + if (actualPayloadClass != Void.class) { + return actualPayloadClass; + } + + // nested generic class - fallback to most outer container + return Class.forName(rawParameterTypeName); + } + + // no generics used - just a normal type + return Class.forName(parameterType.getTypeName()); + } catch (Exception ex) { + log.info("Unable to extract generic data type of %s".formatted(parameterType), ex); + } + return Void.class; + } + + private Class<?> extractActualGenericClass(ParameterizedType parameterType, String rawParameterTypeName) { + Type type = parameterType; + String typeName = rawParameterTypeName; + + while (type instanceof ParameterizedType && extractableClassToArgumentIndex.containsKey(typeName)) { + Integer index = extractableClassToArgumentIndex.get(rawParameterTypeName); + + type = ((ParameterizedType) type).getActualTypeArguments()[index]; + + typeName = type.getTypeName(); + if (type instanceof ParameterizedType) { + typeName = ((ParameterizedType) type).getRawType().getTypeName(); + } + } + + try { + return Class.forName(typeName); + } catch (ClassNotFoundException ex) { + log.debug("Unable to find class for type %s".formatted(typeName), ex); + } + + return Void.class; + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java index 6cee589b..16ac6204 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java @@ -10,6 +10,7 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.operations.Operation import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.operations.OperationMerger; import lombok.extern.slf4j.Slf4j; @@ -28,11 +29,13 @@ public class AsyncAnnotationOperationsScanner<A extends Annotation> extends Asyn ClassScanner classScanner, ComponentsService componentsService, PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, List<OperationBindingProcessor> operationBindingProcessors, List<MessageBindingProcessor> messageBindingProcessors) { super( asyncAnnotationProvider, payloadClassExtractor, + payloadService, componentsService, operationBindingProcessors, messageBindingProcessors); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java index 74b0db0c..81166950 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java @@ -10,7 +10,7 @@ import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeadersBuilder; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.ClassLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import lombok.extern.slf4j.Slf4j; @@ -32,14 +32,14 @@ public class SpringAnnotationClassLevelOperationsScanner< Class<MethodAnnotation> methodAnnotationClass, BindingFactory<ClassAnnotation> bindingFactory, AsyncHeadersBuilder asyncHeadersBuilder, - PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, ComponentsService componentsService) { super( classAnnotationClass, methodAnnotationClass, bindingFactory, asyncHeadersBuilder, - payloadClassExtractor, + payloadService, componentsService); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java index e222893f..ac5448ac 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java @@ -11,7 +11,8 @@ import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeadersBuilder; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.MethodLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import lombok.extern.slf4j.Slf4j; @@ -28,17 +29,17 @@ public class SpringAnnotationMethodLevelOperationsScanner<MethodAnnotation exten extends MethodLevelAnnotationScanner<MethodAnnotation> implements SpringAnnotationOperationsScannerDelegator { private final Class<MethodAnnotation> methodAnnotationClass; - private final PayloadClassExtractor payloadClassExtractor; + private final PayloadService payloadService; public SpringAnnotationMethodLevelOperationsScanner( Class<MethodAnnotation> methodAnnotationClass, BindingFactory<MethodAnnotation> bindingFactory, AsyncHeadersBuilder asyncHeadersBuilder, - PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, ComponentsService componentsService) { super(bindingFactory, asyncHeadersBuilder, componentsService); this.methodAnnotationClass = methodAnnotationClass; - this.payloadClassExtractor = payloadClassExtractor; + this.payloadService = payloadService; } @Override @@ -61,13 +62,13 @@ public class SpringAnnotationMethodLevelOperationsScanner<MethodAnnotation exten String channelName = bindingFactory.getChannelName(annotation); String operationId = channelName + "_" + OperationAction.RECEIVE + "_" + method.getName(); - Class<?> payload = payloadClassExtractor.extractFrom(method); + NamedSchemaObject payloadSchema = payloadService.extractSchema(method); - Operation operation = buildOperation(annotation, payload); + Operation operation = buildOperation(annotation, payloadSchema); return Map.entry(operationId, operation); } - private Operation buildOperation(MethodAnnotation annotation, Class<?> payloadType) { + private Operation buildOperation(MethodAnnotation annotation, NamedSchemaObject payloadType) { MessageObject message = buildMessage(annotation, payloadType); return buildOperation(annotation, message); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java index b8284b26..2851142c 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java @@ -28,6 +28,8 @@ import io.github.springwolf.core.asyncapi.operations.OperationsService; import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; +import io.github.springwolf.core.asyncapi.scanners.common.payload.TypeToClassConverter; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import io.github.springwolf.core.configuration.docket.DefaultAsyncApiDocketService; import io.github.springwolf.core.configuration.properties.SpringwolfConfigConstants; @@ -161,7 +163,22 @@ public class SpringwolfAutoConfiguration { @Bean @ConditionalOnMissingBean - public PayloadClassExtractor payloadClassExtractor(SpringwolfConfigProperties springwolfConfigProperties) { - return new PayloadClassExtractor(springwolfConfigProperties); + public TypeToClassConverter typeToClassConverter(SpringwolfConfigProperties springwolfConfigProperties) { + return new TypeToClassConverter(springwolfConfigProperties); + } + + @Bean + @ConditionalOnMissingBean + public PayloadClassExtractor payloadClassExtractor(TypeToClassConverter typeToClassConverter) { + return new PayloadClassExtractor(typeToClassConverter); + } + + @Bean + @ConditionalOnMissingBean + public PayloadService payloadService( + PayloadClassExtractor payloadClassExtractor, + ComponentsService componentsService, + SpringwolfConfigProperties properties) { + return new PayloadService(payloadClassExtractor, componentsService, properties); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java index a0c9e7d8..ab416da7 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java @@ -17,6 +17,7 @@ import io.github.springwolf.core.asyncapi.scanners.classes.spring.ComponentClass import io.github.springwolf.core.asyncapi.scanners.classes.spring.ConfigurationClassScanner; import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.AsyncAnnotationOperationsScanner; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -74,6 +75,7 @@ public class SpringwolfScannerConfiguration { ComponentsService componentsService, AsyncApiDocketService asyncApiDocketService, PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, List<OperationBindingProcessor> operationBindingProcessors, List<MessageBindingProcessor> messageBindingProcessors) { return new AsyncAnnotationChannelsScanner<>( @@ -82,6 +84,7 @@ public class SpringwolfScannerConfiguration { componentsService, asyncApiDocketService, payloadClassExtractor, + payloadService, operationBindingProcessors, messageBindingProcessors); } @@ -96,6 +99,7 @@ public class SpringwolfScannerConfiguration { SpringwolfClassScanner springwolfClassScanner, ComponentsService componentsService, PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, List<OperationBindingProcessor> operationBindingProcessors, List<MessageBindingProcessor> messageBindingProcessors) { return new AsyncAnnotationOperationsScanner<>( @@ -103,6 +107,7 @@ public class SpringwolfScannerConfiguration { springwolfClassScanner, componentsService, payloadClassExtractor, + payloadService, operationBindingProcessors, messageBindingProcessors); } @@ -118,6 +123,7 @@ public class SpringwolfScannerConfiguration { ComponentsService componentsService, AsyncApiDocketService asyncApiDocketService, PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, List<OperationBindingProcessor> operationBindingProcessors, List<MessageBindingProcessor> messageBindingProcessors) { return new AsyncAnnotationChannelsScanner<>( @@ -126,6 +132,7 @@ public class SpringwolfScannerConfiguration { componentsService, asyncApiDocketService, payloadClassExtractor, + payloadService, operationBindingProcessors, messageBindingProcessors); } @@ -140,6 +147,7 @@ public class SpringwolfScannerConfiguration { SpringwolfClassScanner springwolfClassScanner, ComponentsService componentsService, PayloadClassExtractor payloadClassExtractor, + PayloadService payloadService, List<OperationBindingProcessor> operationBindingProcessors, List<MessageBindingProcessor> messageBindingProcessors) { return new AsyncAnnotationOperationsScanner<>( @@ -147,6 +155,7 @@ public class SpringwolfScannerConfiguration { springwolfClassScanner, componentsService, payloadClassExtractor, + payloadService, operationBindingProcessors, messageBindingProcessors); } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java index 39b2002d..7e4bdb5c 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java @@ -28,6 +28,8 @@ import io.github.springwolf.core.asyncapi.scanners.channels.AsyncAnnotationChann import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; +import io.github.springwolf.core.asyncapi.scanners.common.payload.TypeToClassConverter; import io.github.springwolf.core.configuration.docket.AsyncApiDocket; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; @@ -85,7 +87,10 @@ class AsyncAnnotationChannelsScannerTest { new DefaultComponentsService(emptyList(), emptyList(), swaggerSchemaUtil, properties); private final AsyncApiDocketService asyncApiDocketService = mock(AsyncApiDocketService.class); - private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(properties); + private final TypeToClassConverter typeToClassConverter = new TypeToClassConverter(properties); + private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(typeToClassConverter); + private final PayloadService payloadService = + new PayloadService(payloadClassExtractor, componentsService, properties); private final List<OperationBindingProcessor> operationBindingProcessors = List.of(new TestOperationBindingProcessor()); @@ -99,6 +104,7 @@ class AsyncAnnotationChannelsScannerTest { componentsService, asyncApiDocketService, payloadClassExtractor, + payloadService, operationBindingProcessors, messageBindingProcessors); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java index 11e2dec6..3671c992 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java @@ -20,6 +20,8 @@ import io.github.springwolf.core.asyncapi.components.examples.walkers.json.Examp import io.github.springwolf.core.asyncapi.components.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadService; +import io.github.springwolf.core.asyncapi.scanners.common.payload.TypeToClassConverter; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import lombok.Data; import lombok.EqualsAndHashCode; @@ -48,7 +50,9 @@ import static org.assertj.core.api.Assertions.assertThat; SpringAnnotationClassLevelChannelsScannerIntegrationTest.TestBindingFactory.class, DefaultComponentsService.class, SwaggerSchemaUtil.class, + PayloadService.class, PayloadClassExtractor.class, + TypeToClassConverter.class, DefaultSchemaWalker.class, SchemaWalkerProvider.class, ExampleJsonValueGenerator.class, @@ -60,7 +64,7 @@ class SpringAnnotationClassLevelChannelsScannerIntegrationTest { BindingFactory<TestClassListener> bindingFactory; @Autowired - PayloadClassExtractor payloadClassExtractor; + PayloadService payloadService; @Autowired ComponentsService componentsService; @@ -74,7 +78,7 @@ class SpringAnnotationClassLevelChannelsScannerIntegrationTest { TestMethodListener.class, this.bindingFactory, new AsyncHeadersNotDocumented(), - payloadClassExtractor, + payloadService, componentsService); } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java index 9f0ba78b..601cf424 100644 ---…
- Loading branch information