diff --git a/springwolf-add-ons/springwolf-json-schema/src/test/java/io/github/springwolf/addons/json_schema/JsonSchemaGeneratorTest.java b/springwolf-add-ons/springwolf-json-schema/src/test/java/io/github/springwolf/addons/json_schema/JsonSchemaGeneratorTest.java index ffec10f17..71f2c8216 100644 --- a/springwolf-add-ons/springwolf-json-schema/src/test/java/io/github/springwolf/addons/json_schema/JsonSchemaGeneratorTest.java +++ b/springwolf-add-ons/springwolf-json-schema/src/test/java/io/github/springwolf/addons/json_schema/JsonSchemaGeneratorTest.java @@ -11,6 +11,7 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; +import io.github.springwolf.core.configuration.properties.PayloadSchemaFormat; import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.BooleanSchema; @@ -42,7 +43,8 @@ class JsonSchemaGeneratorTest { @MethodSource void validateJsonSchemaTest(String expectedJsonSchema, Supplier> asyncApiSchema) throws Exception { // given - SchemaObject actualSchema = swaggerSchemaUtil.mapSchema(asyncApiSchema.get()); + ComponentSchema actualSchema = + swaggerSchemaUtil.mapSchema(asyncApiSchema.get(), PayloadSchemaFormat.ASYNCAPI_V3); // when verifyValidJsonSchema(expectedJsonSchema); @@ -67,7 +69,7 @@ void validateJsonSchemaTest(String expectedJsonSchema, Supplier> async ComponentSchema.of(pongSchema)); // when - Object jsonSchema = jsonSchemaGenerator.fromSchema(ComponentSchema.of(actualSchema), definitions); + Object jsonSchema = jsonSchemaGenerator.fromSchema(actualSchema, definitions); // then String jsonSchemaString = mapper.writeValueAsString(jsonSchema); diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java index 91913f8fd..885f03b85 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java @@ -49,4 +49,11 @@ public class MultiFormatSchema extends ExtendableObject { */ @JsonProperty(value = "schema") private Object schema; + + public static MultiFormatSchema of(Object schema) { + // if payloadSchema.payload is already an instance of MultiFormatSchema, do not wrap again. + return (schema instanceof MultiFormatSchema mfs) + ? mfs + : MultiFormatSchema.builder().schema(schema).build(); + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaFormat.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaFormat.java index e15d95255..aef76b112 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaFormat.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/schema/SchemaFormat.java @@ -12,6 +12,7 @@ public enum SchemaFormat { ASYNCAPI_V3_JSON("application/vnd.aai.asyncapi+json;version=" + AsyncAPI.ASYNCAPI_DEFAULT_VERSION), ASYNCAPI_V3_YAML("application/vnd.aai.asyncapi+yaml;version=" + AsyncAPI.ASYNCAPI_DEFAULT_VERSION), OPENAPI_V3("application/vnd.oai.openapi;version=3.0.0"), + OPENAPI_V3_1("application/vnd.oai.openapi;version=3.1.0"), OPENAPI_V3_JSON("application/vnd.oai.openapi+json;version=3.0.0"), OPENAPI_V3_YAML("application/vnd.oai.openapi+yaml;version=3.0.0"), JSON_SCHEMA_JSON("application/schema+json;version=draft-07"), 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 9e50b4a0f..7010198b1 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 @@ -6,6 +6,7 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import jakarta.annotation.Nullable; @@ -33,17 +34,17 @@ public interface ComponentsService { * * @param type Type to resolve a schema from * @param contentType Runtime ContentType of Schema - * @return the root schema for the given type. + * @return a {@link SchemaReference} referencing the root schema, or null if no schema could be resolved. */ @Nullable ComponentSchema resolvePayloadSchema(Type type, String contentType); /** * registers the given schema with this {@link ComponentsService} - * @param headers the schema to register, typically a header schema + * @param schemaWithoutRef the schema to register, typically a header schema * @return the title attribute of the given schema */ - String registerSchema(SchemaObject headers); + String registerSchema(SchemaObject schemaWithoutRef); /** * Provides a map of all registered messages. 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 c5eeba1d4..e27cad7be 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 @@ -7,6 +7,7 @@ import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; +import io.github.springwolf.core.configuration.properties.PayloadSchemaFormat; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -51,12 +52,14 @@ public Map getSchemas() { * * @param type Type to resolve a schema from * @param contentType Runtime ContentType of Schema - * @return the root schema for the given type. + * @return the root schema for the given type */ @Override public ComponentSchema resolvePayloadSchema(Type type, String contentType) { - - SwaggerSchemaService.ExtractedSchemas payload = schemaService.resolveSchema(type, contentType); + PayloadSchemaFormat payloadSchemaFormat = + springwolfConfigProperties.getDocket().getPayloadSchemaFormat(); + SwaggerSchemaService.ExtractedSchemas payload = + schemaService.resolveSchema(type, contentType, payloadSchemaFormat); payload.referencedSchemas().forEach(schemas::putIfAbsent); return payload.rootSchema(); } @@ -65,21 +68,21 @@ public ComponentSchema resolvePayloadSchema(Type type, String contentType) { * registers the given schema with this {@link ComponentsService}. *

NOTE

* Use only with schemas with max. one level of properties. Providing {@link SchemaObject}s with deep - * property hierarchy will result in an corrupted result. + * property hierarchy will result in a corrupted result. *
- * A typical usecase for this method is registering of header schemas, which have typically a simple structure. + * A typical usecase for this method is registering of header schemas, which have typically a simple structure. * - * @param headers the schema to register, typically a header schema + * @param schemaWithoutRef the schema to register, typically a header schema * @return the title attribute of the given schema */ @Override - public String registerSchema(SchemaObject headers) { - log.debug("Registering schema for {}", headers.getTitle()); + public String registerSchema(SchemaObject schemaWithoutRef) { + log.debug("Registering schema for {}", schemaWithoutRef.getTitle()); - SchemaObject headerSchema = schemaService.extractSchema(headers); - this.schemas.putIfAbsent(headers.getTitle(), ComponentSchema.of(headerSchema)); + ComponentSchema processedSchema = schemaService.postProcessSchemaWithoutRef(schemaWithoutRef); + this.schemas.putIfAbsent(schemaWithoutRef.getTitle(), processedSchema); - return headers.getTitle(); + return schemaWithoutRef.getTitle(); } /** diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java index 96f8322da..9c8664ece 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.models.media.StringSchema; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import java.text.SimpleDateFormat; @@ -175,7 +176,14 @@ private Optional buildExampleFromUnvisitedSchema( return composedSchemaExample; } - String type = schema.getType(); + // schema may be an openapi v3 or v3.1 schema. While v3 uses an simple 'type' field, v3.1 supports a set of + // types, for example ["string", "null"]. + + String type = getTypeForExampleValue(schema); + if (type == null) { + return Optional.empty(); + } + return switch (type) { case "array" -> buildArrayExample(schema, definitions, visited); case "boolean" -> exampleValueGenerator.createBooleanExample(DEFAULT_BOOLEAN_EXAMPLE, schema); @@ -235,6 +243,33 @@ private String getFirstEnumValue(Schema schema) { return null; } + /** + * looks in schemas openapi-v3 'type' and openapi-v3.1 'types' fields to + * find the best candidate to use as an example value. + * + * @param schema + * @return the type to use for example values, or null if no suitable type was found. + */ + @Nullable + String getTypeForExampleValue(Schema schema) { + // if the single type field is present, it has precedence over the types field + if (schema.getType() != null) { + return schema.getType(); + } + + Set types = schema.getTypes(); + + if (types == null || types.isEmpty()) { + return null; + } + + return types.stream() + .filter(t -> !"null".equals(t)) + .sorted() // sort types to be deterministic + .findFirst() + .orElse(null); + } + private Optional buildFromComposedSchema( Optional name, Schema schema, Map definitions, Set visited) { final List schemasAllOf = schema.getAllOf(); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/grouping/GroupingService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/grouping/GroupingService.java index 5af1588aa..0e5487efe 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/grouping/GroupingService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/grouping/GroupingService.java @@ -203,7 +203,7 @@ private void markSchemas(AsyncAPI fullAsyncApi, MarkingContext markingContext, S * properties, allOf, anyOf, oneOf, not- and items references. Trys to deduce the schema id from the ref path and * returns a Set of detected schema ids. * - * @param markingContext the current {@link MarkingContext} + * @param markingContext the current {@link MarkingContext} * @param componentSchema the {@link ComponentSchema} to analyze * @return Set of schema ids representing nested schema refs */ @@ -217,14 +217,16 @@ private static Set findUnmarkedNestedSchemas( if (componentSchema.getMultiFormatSchema() != null) { MultiFormatSchema multiFormatSchema = componentSchema.getMultiFormatSchema(); - // Currently we support async_api and open_api format. + // Currently we support async_api and open_api v3 and v3.1 format. // The concrete schemaformat mediatype can contain json/yaml postfix, so we check wether the begin of the // media type matches. - if (multiFormatSchema.getSchemaFormat().startsWith(SchemaFormat.ASYNCAPI_V3.toString()) + String schemaFormat = multiFormatSchema.getSchemaFormat(); + if (schemaFormat.startsWith(SchemaFormat.ASYNCAPI_V3.toString()) && multiFormatSchema.getSchema() instanceof SchemaObject schemaObject) { return findUnmarkedNestedSchemasForAsyncAPISchema(markingContext, schemaObject); } - if (multiFormatSchema.getSchemaFormat().startsWith(SchemaFormat.OPENAPI_V3.toString()) + if ((schemaFormat.startsWith(SchemaFormat.OPENAPI_V3.toString()) + || schemaFormat.startsWith(SchemaFormat.OPENAPI_V3_1.toString())) && multiFormatSchema.getSchema() instanceof Schema openapiSchema) { return findUnmarkedNestedSchemasForOpenAPISchema(markingContext, openapiSchema); } @@ -240,7 +242,7 @@ private static Set findUnmarkedNestedSchemas( * returns a Set of detected schema ids. * * @param markingContext the current {@link MarkingContext} - * @param schema the {@link SchemaObject} to analyze + * @param schema the {@link SchemaObject} to analyze * @return Set of schema ids representing nested schema refs */ private static Set findUnmarkedNestedSchemasForAsyncAPISchema( @@ -276,12 +278,17 @@ private static Set findUnmarkedNestedSchemasForAsyncAPISchema( * returns a Set of detected schema ids. * * @param markingContext the current {@link MarkingContext} - * @param openapiSchema the Swagger {@link Schema} to analyze + * @param openapiSchema the Swagger {@link Schema} to analyze * @return Set of schema ids representing nested schema refs */ private static Set findUnmarkedNestedSchemasForOpenAPISchema( MarkingContext markingContext, Schema openapiSchema) { - Stream propertySchemas = openapiSchema.getProperties().values().stream(); + final Stream propertySchemas; + if (openapiSchema.getProperties() != null) { + propertySchemas = openapiSchema.getProperties().values().stream(); + } else { + propertySchemas = Stream.empty(); + } Stream referencedSchemas = Stream.of( openapiSchema.getAllOf(), openapiSchema.getAnyOf(), openapiSchema.getOneOf()) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractor.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractor.java index 0708f7d7d..985527638 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractor.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractor.java @@ -34,7 +34,8 @@ public SchemaObject extractHeader(Method method, PayloadSchemaObject payload) { Header headerAnnotation = argument.getAnnotation(Header.class); String headerName = getHeaderAnnotationName(headerAnnotation); - SwaggerSchemaService.ExtractedSchemas extractedSchema = schemaService.extractSchema(argument.getType()); + SwaggerSchemaService.ExtractedSchemas extractedSchema = + schemaService.postProcessSimpleSchema(argument.getType()); ComponentSchema rootComponentSchema = extractedSchema.rootSchema(); // to stay compatible with former versions. diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java index 845f8471b..1662c8efd 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java @@ -42,8 +42,8 @@ public MessageObject buildMessage(AsyncOperation operationData, Method method) { Map messageBinding = AsyncAnnotationUtil.processMessageBindingFromAnnotation(method, messageBindingProcessors); - var messagePayload = MessagePayload.of( - MultiFormatSchema.builder().schema(payloadSchema.payload()).build()); + MultiFormatSchema multiFormatSchema = MultiFormatSchema.of(payloadSchema.payload()); + MessagePayload messagePayload = MessagePayload.of(multiFormatSchema); var builder = MessageObject.builder() .messageId(payloadSchema.name()) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java index 14ce82f4c..21cb3efd6 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java @@ -36,6 +36,14 @@ public PayloadSchemaObject buildSchema(Type payloadType) { return buildSchema(contentType, payloadType); } + /** + * creates a {@link PayloadSchemaObject} from the given type and content type. Registers the created schema objects + * with this {@link ComponentsService}. + * + * @param contentType + * @param payloadType + * @return + */ public PayloadSchemaObject buildSchema(String contentType, Type payloadType) { String schemaName = componentsService.getSchemaName(payloadType); String simpleSchemaName = componentsService.getSimpleSchemaName(payloadType); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/ModelConvertersProvider.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/ModelConvertersProvider.java new file mode 100644 index 000000000..5bfb1adcd --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/ModelConvertersProvider.java @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.schemas; + +import io.github.springwolf.asyncapi.v3.model.schema.SchemaFormat; +import io.github.springwolf.core.configuration.properties.PayloadSchemaFormat; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverters; + +import java.util.List; + +/** + * Provides fully prepared {@link io.swagger.v3.core.converter.ModelConverters} for openapi v3 and v3.1 + * requirements. + */ +public class ModelConvertersProvider { + + private final ModelConverters converter_openapi30; + private final ModelConverters converter_openapi31; + + public ModelConvertersProvider(List externalModelConverters) { + converter_openapi30 = new ModelConverters(false); + converter_openapi31 = new ModelConverters(true); + externalModelConverters.forEach(converter_openapi30::addConverter); + externalModelConverters.forEach(converter_openapi31::addConverter); + } + + /** + * provides the appropriate {@link ModelConverters} for the given {@link SchemaFormat}. + * + * @param schemaFormat the schemaFormat that shall be generated. + * @return the appropriate {@link ModelConverters} or {@link IllegalArgumentException} if the given format is not supported. + */ + public ModelConverters getModelConverterFor(PayloadSchemaFormat schemaFormat) { + return switch (schemaFormat) { + case ASYNCAPI_V3, OPENAPI_V3 -> converter_openapi30; + case OPENAPI_V3_1 -> converter_openapi31; + }; + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java index 8ef9a69d6..e3db527cc 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java @@ -7,9 +7,9 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.annotations.AsyncApiPayload; import io.github.springwolf.core.asyncapi.components.postprocessors.SchemasPostProcessor; +import io.github.springwolf.core.configuration.properties.PayloadSchemaFormat; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import io.swagger.v3.core.converter.AnnotatedType; -import io.swagger.v3.core.converter.ModelConverter; import io.swagger.v3.core.converter.ModelConverters; import io.swagger.v3.core.converter.ResolvedSchema; import io.swagger.v3.core.jackson.TypeNameResolver; @@ -18,6 +18,7 @@ import io.swagger.v3.core.util.RefUtils; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -34,23 +35,13 @@ import static io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties.ConfigDocket.DEFAULT_CONTENT_TYPE; @Slf4j +@RequiredArgsConstructor public class SwaggerSchemaService { - private final ModelConverters converter = ModelConverters.getInstance(); + private final List schemaPostProcessors; private final SwaggerSchemaUtil swaggerSchemaUtil; private final SpringwolfConfigProperties properties; - - public SwaggerSchemaService( - List externalModelConverters, - List schemaPostProcessors, - SwaggerSchemaUtil swaggerSchemaUtil, - SpringwolfConfigProperties properties) { - - externalModelConverters.forEach(converter::addConverter); - this.schemaPostProcessors = schemaPostProcessors; - this.swaggerSchemaUtil = swaggerSchemaUtil; - this.properties = properties; - } + private final ModelConvertersProvider modelConvertersProvider; public record ExtractedSchemas(ComponentSchema rootSchema, Map referencedSchemas) {} @@ -60,27 +51,27 @@ public record ExtractedSchemas(ComponentSchema rootSchema, MapNOTE

* The conversion between the AsyncApi {@link SchemaObject} and Swagger schema instance is not a 'full conversion'. Only - * root attributes of the schema an the first level of properties a converted. Providing {@link SchemaObject}s with deep - * property hierarchy will result in an corrupted result. + * root attributes of the schema and the first level of properties are converted. Providing {@link SchemaObject}s with deep + * property hierarchy will result in a corrupted result. *
* A typical usecase for this method is postprocessing of header schemas, which have typically a simple structure. * - * @param headers + * @param schemaWithoutRef * @return */ - public SchemaObject extractSchema(SchemaObject headers) { - String schemaName = headers.getTitle(); + public ComponentSchema postProcessSchemaWithoutRef(SchemaObject schemaWithoutRef) { + String schemaName = schemaWithoutRef.getTitle(); // create a swagger schema to invoke the postprocessors. Copy attributes vom headers to (Swagger) headerSchema ObjectSchema headerSchema = new ObjectSchema(); headerSchema.setName(schemaName); - headerSchema.setTitle(headers.getTitle()); - headerSchema.setDescription(headers.getDescription()); + headerSchema.setTitle(schemaWithoutRef.getTitle()); + headerSchema.setDescription(schemaWithoutRef.getDescription()); // transform properties of headers to a properties Map of Swagger schemas. // (Only one level, no deep transformation, see SwaggerSchemaUtil#mapToSwagger) // - Map properties = headers.getProperties().entrySet().stream() + Map properties = schemaWithoutRef.getProperties().entrySet().stream() .map((property) -> Map.entry(property.getKey(), (Schema) swaggerSchemaUtil.mapToSwagger(property.getValue()))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); @@ -90,25 +81,40 @@ public SchemaObject extractSchema(SchemaObject headers) { Map newSchemasToProcess = Map.of(schemaName, headerSchema); postProcessSchemas(newSchemasToProcess, new HashMap<>(newSchemasToProcess), DEFAULT_CONTENT_TYPE); - // convert Swagger schema back to an AsnycApi SchemaObject - return swaggerSchemaUtil.mapSchema(headerSchema); + // convert Swagger schema back to an AsyncApi SchemaObject + return swaggerSchemaUtil.mapSchema(headerSchema, PayloadSchemaFormat.ASYNCAPI_V3); } - public ExtractedSchemas extractSchema(Class type) { - return this.resolveSchema(type, ""); + public ExtractedSchemas postProcessSimpleSchema(Class type) { + return this.resolveSchema(type, "", PayloadSchemaFormat.ASYNCAPI_V3); } - public ExtractedSchemas resolveSchema(Type type, String contentType) { + /** + * creates a {@link ExtractedSchemas} from the given type. The resulting ExtractedSchemas will contain the root + * schema (which is always a schema ref) and a List of conrecte schemas referenced from the root schema. + * + * @param type + * @param contentType + * @param payloadSchemaFormat SchemaFormat to use + * @return + */ + public ExtractedSchemas resolveSchema(Type type, String contentType, PayloadSchemaFormat payloadSchemaFormat) { String actualContentType = StringUtils.isBlank(contentType) ? properties.getDocket().getDefaultContentType() : contentType; + + // use swagger to resolve type to a swagger ResolvedSchema Object. + ModelConverters converterToUse = modelConvertersProvider.getModelConverterFor(payloadSchemaFormat); + ResolvedSchema resolvedSchema = runWithFqnSetting( - (unused) -> converter.resolveAsResolvedSchema(new AnnotatedType(type).resolveAsRef(true))); + (unused) -> converterToUse.resolveAsResolvedSchema(new AnnotatedType(type).resolveAsRef(true))); if (resolvedSchema == null) { // defaulting to stringSchema when resolvedSchema is null - SchemaObject payloadSchema = swaggerSchemaUtil.mapSchema( - PrimitiveType.fromType(String.class).createProperty()); - return new ExtractedSchemas(ComponentSchema.of(payloadSchema), Map.of()); + Schema stringPropertySchema = + PrimitiveType.fromType(String.class).createProperty(); + ComponentSchema stringComponentSchema = + swaggerSchemaUtil.mapSchema(stringPropertySchema, payloadSchemaFormat); + return new ExtractedSchemas(stringComponentSchema, Map.of()); } else { Map newSchemasToProcess = new LinkedHashMap<>(resolvedSchema.referencedSchemas); newSchemasToProcess.putIfAbsent(getNameFromType(type), resolvedSchema.schema); @@ -117,7 +123,7 @@ public ExtractedSchemas resolveSchema(Type type, String contentType) { HashMap processedSchemas = new HashMap<>(newSchemasToProcess); postProcessSchemas(newSchemasToProcess, processedSchemas, actualContentType); - return createExtractedSchemas(resolvedSchema.schema, processedSchemas); + return createExtractedSchemas(resolvedSchema.schema, processedSchemas, payloadSchemaFormat); } } @@ -126,15 +132,14 @@ public ExtractedSchemas resolveSchema(Type type, String contentType) { * * @param rootSchema Swagger root schema * @param referencedSchemas all referenced swagger schemas + * @param payloadSchemaFormat the schema-format of the schemas inside the resulting ExtractedSchemas * @return */ - private ExtractedSchemas createExtractedSchemas(Schema rootSchema, Map referencedSchemas) { - ComponentSchema rootComponentSchema = swaggerSchemaUtil.mapSchemaOrRef(rootSchema); - Map referencedSchemaObjects = swaggerSchemaUtil.mapSchemasMap(referencedSchemas); - Map referencedComponentSchemas = new HashMap<>(); - referencedSchemaObjects.forEach((schemaname, schemaobject) -> { - referencedComponentSchemas.put(schemaname, ComponentSchema.of(schemaobject)); - }); + private ExtractedSchemas createExtractedSchemas( + Schema rootSchema, Map referencedSchemas, PayloadSchemaFormat payloadSchemaFormat) { + ComponentSchema rootComponentSchema = swaggerSchemaUtil.mapSchemaOrRef(rootSchema, payloadSchemaFormat); + Map referencedComponentSchemas = + swaggerSchemaUtil.mapSchemasMap(referencedSchemas, payloadSchemaFormat); return new ExtractedSchemas(rootComponentSchema, referencedComponentSchemas); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java index b8311c328..c4ce7af60 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java @@ -4,10 +4,10 @@ import io.github.springwolf.asyncapi.v3.model.ExternalDocumentation; import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaFormat; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; +import io.github.springwolf.core.configuration.properties.PayloadSchemaFormat; import io.swagger.v3.oas.models.media.Schema; import lombok.RequiredArgsConstructor; import org.springframework.lang.Nullable; @@ -25,9 +25,9 @@ @RequiredArgsConstructor public class SwaggerSchemaUtil { - public Map mapSchemasMap(Map schemaMap) { + public Map mapSchemasMap(Map schemaMap, PayloadSchemaFormat schemaFormat) { return schemaMap.entrySet().stream() - .map(entry -> Map.entry(entry.getKey(), mapSchema(entry.getValue()))) + .map(entry -> Map.entry(entry.getKey(), mapSchema(entry.getValue(), schemaFormat))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } @@ -37,28 +37,49 @@ public Map mapSchemasMap(Map schemaMap) { * referenced location. Otherwise, the given Swagger schema is converted to an AsnycApi {@link SchemaObject} and * put into the resulting {@link ComponentSchema} * - * @param schema the Swagger schema to convert + * @param swaggerSchema the Swagger schema to convert + * @param payloadSchemaFormat the schema format of the resulting schema * @return ComponentSchema with either a {@link SchemaReference} or a {@link SchemaObject}. */ - public ComponentSchema mapSchemaOrRef(Schema schema) { - if (schema.get$ref() != null) { - return ComponentSchema.of(new SchemaReference(schema.get$ref())); + public ComponentSchema mapSchemaOrRef(Schema swaggerSchema, PayloadSchemaFormat payloadSchemaFormat) { + if (swaggerSchema.get$ref() != null) { + return ComponentSchema.of(new SchemaReference(swaggerSchema.get$ref())); } - return ComponentSchema.of(mapSchema(schema)); + return mapSchema(swaggerSchema, payloadSchemaFormat); } /** - * Converts the given Swagger schema to a AsnycApi {@link SchemaObject}. Properties are mapped recursively except - * as long as the child schemas are 'real' schems and not schema references. So this method performs a deep conversion + * Converts the given Swagger schema to a {ComponentSchema} with a given schemaFormat. + * If schemaFormat is an openapi format, the given swaggerSchema is simply wrapped to an {@link ComponentSchema}. + *

+ * Properties are mapped recursively except + * as long as the child schemas are 'real' schemas and not schema references. So this method performs a deep conversion * of the entire Swagger schema. * - * @param value the given Swagger schema instance + * @param + * @param swaggerSchema the given Swagger schema instance + * @param payloadSchemaFormat * @return the resulting AsnycApi SchemaObject */ - public SchemaObject mapSchema(Schema value) { + public ComponentSchema mapSchema(Schema swaggerSchema, PayloadSchemaFormat payloadSchemaFormat) { + return switch (payloadSchemaFormat) { + case OPENAPI_V3, OPENAPI_V3_1 -> ComponentSchema.of( + new MultiFormatSchema(payloadSchemaFormat.getSchemaFormat().value, swaggerSchema)); + case ASYNCAPI_V3 -> ComponentSchema.of(mapSwaggerSchemaToAsyncApiSchema(swaggerSchema)); + }; + } + + /** + * transforms the given Swagger schema to an AsyncApi schema. + * + * @param swaggerSchema + * @return + */ + private SchemaObject mapSwaggerSchemaToAsyncApiSchema(Schema swaggerSchema) { + SchemaObject.SchemaObjectBuilder builder = SchemaObject.builder(); - io.swagger.v3.oas.models.ExternalDocumentation externalDocs = value.getExternalDocs(); + io.swagger.v3.oas.models.ExternalDocumentation externalDocs = swaggerSchema.getExternalDocs(); if (externalDocs != null) { ExternalDocumentation externalDocumentation = ExternalDocumentation.builder() .description(externalDocs.getDescription()) @@ -67,48 +88,49 @@ public SchemaObject mapSchema(Schema value) { builder.externalDocs(externalDocumentation); } - builder.deprecated(value.getDeprecated()); + builder.deprecated(swaggerSchema.getDeprecated()); - builder.title(value.getTitle()); + builder.title(swaggerSchema.getTitle()); - boolean isNullable = Boolean.TRUE.equals(value.getNullable()); - assignType(value, builder, isNullable); + boolean isNullable = Boolean.TRUE.equals(swaggerSchema.getNullable()); + assignType(swaggerSchema, builder, isNullable); - Map properties = value.getProperties(); + Map properties = swaggerSchema.getProperties(); if (properties != null) { Map propertiesMapped = properties.entrySet().stream() - .map(entry -> Map.entry(entry.getKey(), mapSchemaOrRef(entry.getValue()))) + .map(entry -> Map.entry( + entry.getKey(), mapSchemaOrRef(entry.getValue(), PayloadSchemaFormat.ASYNCAPI_V3))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); builder.properties(propertiesMapped); } - builder.description(value.getDescription()); + builder.description(swaggerSchema.getDescription()); - builder.format(value.getFormat()); - builder.pattern(value.getPattern()); + builder.format(swaggerSchema.getFormat()); + builder.pattern(swaggerSchema.getPattern()); - if (value.getExclusiveMinimum() != null && value.getExclusiveMinimum()) { - builder.exclusiveMinimum(value.getMinimum()); - } else if (value.getExclusiveMinimumValue() != null) { - builder.exclusiveMinimum(value.getExclusiveMinimumValue()); + if (swaggerSchema.getExclusiveMinimum() != null && swaggerSchema.getExclusiveMinimum()) { + builder.exclusiveMinimum(swaggerSchema.getMinimum()); + } else if (swaggerSchema.getExclusiveMinimumValue() != null) { + builder.exclusiveMinimum(swaggerSchema.getExclusiveMinimumValue()); } else { - builder.minimum(value.getMinimum()); + builder.minimum(swaggerSchema.getMinimum()); } - if (value.getExclusiveMaximum() != null && value.getExclusiveMaximum()) { - builder.exclusiveMaximum(value.getMaximum()); - } else if (value.getExclusiveMaximumValue() != null) { - builder.exclusiveMaximum(value.getExclusiveMaximumValue()); + if (swaggerSchema.getExclusiveMaximum() != null && swaggerSchema.getExclusiveMaximum()) { + builder.exclusiveMaximum(swaggerSchema.getMaximum()); + } else if (swaggerSchema.getExclusiveMaximumValue() != null) { + builder.exclusiveMaximum(swaggerSchema.getExclusiveMaximumValue()); } else { - builder.maximum(value.getMaximum()); + builder.maximum(swaggerSchema.getMaximum()); } - builder.multipleOf(value.getMultipleOf()); + builder.multipleOf(swaggerSchema.getMultipleOf()); - builder.minLength(value.getMinLength()); - builder.maxLength(value.getMaxLength()); + builder.minLength(swaggerSchema.getMinLength()); + builder.maxLength(swaggerSchema.getMaxLength()); - List anEnum = value.getEnum(); + List anEnum = swaggerSchema.getEnum(); if (anEnum != null) { List enumStringValues = anEnum.stream().map(Object::toString).collect(Collectors.toCollection(ArrayList::new)); @@ -118,75 +140,74 @@ public SchemaObject mapSchema(Schema value) { builder.enumValues(enumStringValues); } - Object example = value.getExample(); + Object example = swaggerSchema.getExample(); if (example != null) { builder.examples(List.of(example)); } - List examples = value.getExamples(); + List examples = swaggerSchema.getExamples(); if (examples != null && !examples.isEmpty()) { builder.examples(examples); } - Object additionalProperties = value.getAdditionalProperties(); + Object additionalProperties = swaggerSchema.getAdditionalProperties(); if (additionalProperties instanceof Schema) { - builder.additionalProperties(mapSchemaOrRef((Schema) additionalProperties)); + builder.additionalProperties( + mapSchemaOrRef((Schema) additionalProperties, PayloadSchemaFormat.ASYNCAPI_V3)); } - builder.required(value.getRequired()); + builder.required(swaggerSchema.getRequired()); - if (value.getDiscriminator() != null) { - builder.discriminator(value.getDiscriminator().getPropertyName()); + if (swaggerSchema.getDiscriminator() != null) { + builder.discriminator(swaggerSchema.getDiscriminator().getPropertyName()); } - List allOf = value.getAllOf(); + List allOf = swaggerSchema.getAllOf(); if (allOf != null) { builder.allOf(allOf.stream() - .filter((el) -> el instanceof Schema) - .map((Object schema) -> mapSchemaOrRef((Schema) schema)) + .map(schema -> mapSchemaOrRef(schema, PayloadSchemaFormat.ASYNCAPI_V3)) .collect(Collectors.toList())); } - List oneOf = value.getOneOf(); + List oneOf = swaggerSchema.getOneOf(); if (oneOf != null) { builder.oneOf(oneOf.stream() - .filter((el) -> el instanceof Schema) - .map((Object schema) -> mapSchemaOrRef((Schema) schema)) + .map(schema -> mapSchemaOrRef(schema, PayloadSchemaFormat.ASYNCAPI_V3)) .collect(Collectors.toList())); } - List anyOf = value.getAnyOf(); + List anyOf = swaggerSchema.getAnyOf(); if (anyOf != null) { builder.anyOf(anyOf.stream() - .filter((el) -> el instanceof Schema) - .map((Object schema) -> mapSchemaOrRef((Schema) schema)) + .map(schema -> mapSchemaOrRef(schema, PayloadSchemaFormat.ASYNCAPI_V3)) .collect(Collectors.toList())); } - builder.constValue(value.getConst()); + builder.constValue(swaggerSchema.getConst()); - Schema not = value.getNot(); + Schema not = swaggerSchema.getNot(); if (not != null) { - builder.not(mapSchemaOrRef(not)); + builder.not(mapSchemaOrRef(not, PayloadSchemaFormat.ASYNCAPI_V3)); } - Schema items = value.getItems(); - if (items != null && "array".equals(value.getType())) { - builder.items(mapSchemaOrRef(items)); + Schema items = swaggerSchema.getItems(); + if (items != null && "array".equals(swaggerSchema.getType())) { + builder.items(mapSchemaOrRef(items, PayloadSchemaFormat.ASYNCAPI_V3)); } - builder.uniqueItems(value.getUniqueItems()); + builder.uniqueItems(swaggerSchema.getUniqueItems()); - builder.minItems(value.getMinItems()); - builder.maxItems(value.getMaxItems()); + builder.minItems(swaggerSchema.getMinItems()); + builder.maxItems(swaggerSchema.getMaxItems()); return builder.build(); } - private static void assignType(Schema value, SchemaObject.SchemaObjectBuilder builder, boolean isNullable) { - Set types = value.getTypes() == null ? new HashSet<>() : new HashSet(value.getTypes()); - if (!types.contains(value.getType())) { + private static void assignType(Schema swaggerSchema, SchemaObject.SchemaObjectBuilder builder, boolean isNullable) { + Set types = + swaggerSchema.getTypes() == null ? new HashSet<>() : new HashSet(swaggerSchema.getTypes()); + if (!types.contains(swaggerSchema.getType())) { // contradicting types; prefer type for backward compatibility // maintainer note: remove condition in next major release - builder.type(value.getType()); + builder.type(swaggerSchema.getType()); return; } @@ -229,12 +250,13 @@ public Object unwrapSchema(Object schema) { *
  • a {@link SchemaReference} which is converted to a Swagger Schema with a $ref reference
  • *
  • a {@link MultiFormatSchema}. In this case, these Mediatypes are supported: *
      - *
    • {@link SchemaFormat#ASYNCAPI_V3}
    • - *
    • {@link SchemaFormat#OPENAPI_V3}
    • + *
    • {@link PayloadSchemaFormat#ASYNCAPI_V3}
    • + *
    • {@link PayloadSchemaFormat#OPENAPI_V3}
    • *
    *
  • * * if no type is matching, a Runtime Exception is thrown. + * * @param schema Object representing an schema. * @return the resulting Schema */ @@ -262,6 +284,7 @@ public Schema mapToSwagger(Object schema) { * This method does not perform a 'deep' transformation, only the root attributes of asyncApiSchema * are mapped to the Swagger schema. The properties of asyncApiSchema will not be mapped to the * Swagger schema. + * * @param asyncApiSchema * @return */ diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfCoreConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfCoreConfiguration.java index ad68cfbf0..f221dd0b6 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfCoreConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfCoreConfiguration.java @@ -38,6 +38,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeExtractor; import io.github.springwolf.core.asyncapi.scanners.common.utils.StringValueResolverProxy; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; @@ -123,12 +124,18 @@ public ComponentsService componentsService( @Bean @ConditionalOnMissingBean public SwaggerSchemaService schemasService( - List modelConverters, List schemaPostProcessors, SwaggerSchemaUtil swaggerSchemaUtil, - SpringwolfConfigProperties springwolfConfigProperties) { + SpringwolfConfigProperties springwolfConfigProperties, + ModelConvertersProvider modelConvertersProvider) { return new SwaggerSchemaService( - modelConverters, schemaPostProcessors, swaggerSchemaUtil, springwolfConfigProperties); + schemaPostProcessors, swaggerSchemaUtil, springwolfConfigProperties, modelConvertersProvider); + } + + @Bean + @ConditionalOnMissingBean + public ModelConvertersProvider modelConvertersProvider(List modelConverters) { + return new ModelConvertersProvider(modelConverters); } @Bean diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/properties/PayloadSchemaFormat.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/properties/PayloadSchemaFormat.java new file mode 100644 index 000000000..3022a4bcc --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/properties/PayloadSchemaFormat.java @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.configuration.properties; + +import io.github.springwolf.asyncapi.v3.model.schema.SchemaFormat; + +/** + * Enumeration defining the supported payload schema formats, for use in SpringwolfConfigProperties. + */ +public enum PayloadSchemaFormat { + ASYNCAPI_V3(SchemaFormat.ASYNCAPI_V3), + OPENAPI_V3(SchemaFormat.OPENAPI_V3), + OPENAPI_V3_1(SchemaFormat.OPENAPI_V3_1); + + private final SchemaFormat schemaFormat; + + PayloadSchemaFormat(SchemaFormat schemaFormat) { + this.schemaFormat = schemaFormat; + } + + public SchemaFormat getSchemaFormat() { + return schemaFormat; + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/properties/SpringwolfConfigProperties.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/properties/SpringwolfConfigProperties.java index dec84aa4b..611daa703 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/properties/SpringwolfConfigProperties.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/properties/SpringwolfConfigProperties.java @@ -141,6 +141,8 @@ public static class ConfigDocket { */ private String defaultContentType = DEFAULT_CONTENT_TYPE; + private PayloadSchemaFormat payloadSchemaFormat = PayloadSchemaFormat.ASYNCAPI_V3; + @Nullable private Map servers; diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java index 90a4b4ad8..ad6865c26 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java @@ -5,8 +5,10 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.annotations.AsyncApiPayload; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; +import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.DiscriminatorMapping; @@ -27,8 +29,13 @@ class DefaultComponentsServiceIntegrationTest { private final SpringwolfConfigProperties configProperties = new SpringwolfConfigProperties(); - private final SwaggerSchemaService schemaService = - new SwaggerSchemaService(List.of(), List.of(), new SwaggerSchemaUtil(), configProperties); + private static final SchemaTitleModelConverter titleModelConverter = new SchemaTitleModelConverter(); + + private final SwaggerSchemaService schemaService = new SwaggerSchemaService( + List.of(), + new SwaggerSchemaUtil(), + configProperties, + new ModelConvertersProvider(List.of(titleModelConverter))); private final ComponentsService componentsService = new DefaultComponentsService(schemaService, configProperties); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java index b5555d95d..0c8827f6b 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java @@ -14,6 +14,7 @@ import io.github.springwolf.core.asyncapi.components.examples.walkers.DefaultSchemaWalker; import io.github.springwolf.core.asyncapi.components.examples.walkers.json.ExampleJsonValueGenerator; import io.github.springwolf.core.asyncapi.components.postprocessors.ExampleGeneratorPostProcessor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; @@ -50,11 +51,11 @@ class DefaultJsonComponentsServiceIntegrationTest { private final SpringwolfConfigProperties springwolfConfigProperties = new SpringwolfConfigProperties(); private final SwaggerSchemaService schemaService = new SwaggerSchemaService( - List.of(new SchemaTitleModelConverter()), List.of(new ExampleGeneratorPostProcessor( new SchemaWalkerProvider(List.of(new DefaultSchemaWalker<>(new ExampleJsonValueGenerator()))))), new SwaggerSchemaUtil(), - springwolfConfigProperties); + springwolfConfigProperties, + new ModelConvertersProvider(List.of(new SchemaTitleModelConverter()))); private final ComponentsService componentsService = new DefaultComponentsService(schemaService, springwolfConfigProperties); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java index a1e5f03fe..fc17f796a 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java @@ -11,6 +11,7 @@ import io.github.springwolf.core.asyncapi.components.examples.walkers.xml.DefaultExampleXmlValueSerializer; import io.github.springwolf.core.asyncapi.components.examples.walkers.xml.ExampleXmlValueGenerator; import io.github.springwolf.core.asyncapi.components.postprocessors.ExampleGeneratorPostProcessor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; @@ -51,11 +52,11 @@ class DefaultXmlComponentsServiceIntegrationTest { private final SpringwolfConfigProperties configProperties = new SpringwolfConfigProperties(); private final SwaggerSchemaService schemaService = new SwaggerSchemaService( - List.of(new SchemaTitleModelConverter()), List.of(new ExampleGeneratorPostProcessor(new SchemaWalkerProvider(List.of( new DefaultSchemaWalker<>(new ExampleXmlValueGenerator(new DefaultExampleXmlValueSerializer())))))), new SwaggerSchemaUtil(), - configProperties); + configProperties, + new ModelConvertersProvider(List.of(new SchemaTitleModelConverter()))); private final ComponentsService componentsService = new DefaultComponentsService(schemaService, configProperties); @Test diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java index 22646e273..a4fbfdbf0 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java @@ -16,6 +16,7 @@ import io.github.springwolf.core.asyncapi.components.examples.walkers.yaml.DefaultExampleYamlValueSerializer; import io.github.springwolf.core.asyncapi.components.examples.walkers.yaml.ExampleYamlValueGenerator; import io.github.springwolf.core.asyncapi.components.postprocessors.ExampleGeneratorPostProcessor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; @@ -54,11 +55,11 @@ class DefaultYamlComponentsServiceIntegrationTest { new ExampleJsonValueGenerator(), new DefaultExampleYamlValueSerializer(), springwolfConfigProperties); private final SwaggerSchemaService schemaService = new SwaggerSchemaService( - List.of(new SchemaTitleModelConverter()), List.of(new ExampleGeneratorPostProcessor( new SchemaWalkerProvider(List.of(new DefaultSchemaWalker<>(exampleYamlValueGenerator))))), new SwaggerSchemaUtil(), - new SpringwolfConfigProperties()); + new SpringwolfConfigProperties(), + new ModelConvertersProvider(List.of(new SchemaTitleModelConverter()))); private final ComponentsService componentsService = new DefaultComponentsService(schemaService, springwolfConfigProperties); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/SwaggerSchemaUtilTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/SwaggerSchemaUtilTest.java index 4216ca489..baadc4f59 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/SwaggerSchemaUtilTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/SwaggerSchemaUtilTest.java @@ -2,10 +2,13 @@ package io.github.springwolf.core.asyncapi.components; import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; +import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaFormat; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; +import io.github.springwolf.core.configuration.properties.PayloadSchemaFormat; import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.media.Discriminator; import io.swagger.v3.oas.models.media.ObjectSchema; @@ -26,6 +29,49 @@ class SwaggerSchemaUtilTest { @Nested class MapSchemaOrRef { + @Test + void mapToOpenApiV3Schema() { + // given + ObjectSchema schema = new ObjectSchema(); + schema.setType(SchemaType.STRING); + ExternalDocumentation externalDocs = new ExternalDocumentation(); + externalDocs.setDescription("description"); + externalDocs.setUrl("url"); + schema.setExternalDocs(externalDocs); + + // when + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchemaOrRef(schema, PayloadSchemaFormat.OPENAPI_V3); + + // then + // componentSchema should contain a MultiFormatSchema with the original openapi schema + MultiFormatSchema multiFormatSchema = componentSchema.getMultiFormatSchema(); + assertThat(multiFormatSchema).isNotNull(); + assertThat(multiFormatSchema.getSchema()).isSameAs(schema); + assertThat(multiFormatSchema.getSchemaFormat()).isEqualTo(SchemaFormat.OPENAPI_V3.value); + } + + @Test + void mapToOpenApiV31Schema() { + // given + ObjectSchema schema = new ObjectSchema(); + schema.setType(SchemaType.STRING); + ExternalDocumentation externalDocs = new ExternalDocumentation(); + externalDocs.setDescription("description"); + externalDocs.setUrl("url"); + schema.setExternalDocs(externalDocs); + + // when + ComponentSchema componentSchema = + swaggerSchemaUtil.mapSchemaOrRef(schema, PayloadSchemaFormat.OPENAPI_V3_1); + + // then + // componentSchema should contain a MultiFormatSchema with the original openapi schema + MultiFormatSchema multiFormatSchema = componentSchema.getMultiFormatSchema(); + assertThat(multiFormatSchema).isNotNull(); + assertThat(multiFormatSchema.getSchema()).isSameAs(schema); + assertThat(multiFormatSchema.getSchemaFormat()).isEqualTo(SchemaFormat.OPENAPI_V3_1.value); + } + @Test void mapReference() { // given @@ -33,7 +79,7 @@ void mapReference() { schema.set$ref("#/components/schemas/MySchema"); // when - ComponentSchema componentSchema = swaggerSchemaUtil.mapSchemaOrRef(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchemaOrRef(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then assertThat(componentSchema.getReference()).isEqualTo(new SchemaReference("#/components/schemas/MySchema")); @@ -46,7 +92,7 @@ void mapSchema() { schema.setType(SchemaType.STRING); // when - ComponentSchema componentSchema = swaggerSchemaUtil.mapSchemaOrRef(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchemaOrRef(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then assertThat(componentSchema.getSchema().getType()).containsExactly(SchemaType.STRING); @@ -55,6 +101,49 @@ void mapSchema() { @Nested class MapSchema { + + @Test + void mapToOpenApiV3Schema() { + // given + ObjectSchema schema = new ObjectSchema(); + schema.setType(SchemaType.STRING); + ExternalDocumentation externalDocs = new ExternalDocumentation(); + externalDocs.setDescription("description"); + externalDocs.setUrl("url"); + schema.setExternalDocs(externalDocs); + + // when + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.OPENAPI_V3); + + // then + // componentSchema should contain a MultiFormatSchema with the original openapi schema + MultiFormatSchema multiFormatSchema = componentSchema.getMultiFormatSchema(); + assertThat(multiFormatSchema).isNotNull(); + assertThat(multiFormatSchema.getSchema()).isSameAs(schema); + assertThat(multiFormatSchema.getSchemaFormat()).isEqualTo(SchemaFormat.OPENAPI_V3.value); + } + + @Test + void mapToOpenApiV31Schema() { + // given + ObjectSchema schema = new ObjectSchema(); + schema.setType(SchemaType.STRING); + ExternalDocumentation externalDocs = new ExternalDocumentation(); + externalDocs.setDescription("description"); + externalDocs.setUrl("url"); + schema.setExternalDocs(externalDocs); + + // when + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.OPENAPI_V3_1); + + // then + // componentSchema should contain a MultiFormatSchema with the original openapi schema + MultiFormatSchema multiFormatSchema = componentSchema.getMultiFormatSchema(); + assertThat(multiFormatSchema).isNotNull(); + assertThat(multiFormatSchema.getSchema()).isSameAs(schema); + assertThat(multiFormatSchema.getSchemaFormat()).isEqualTo(SchemaFormat.OPENAPI_V3_1.value); + } + @Test void mapExternalDocs() { // given @@ -65,11 +154,12 @@ void mapExternalDocs() { schema.setExternalDocs(externalDocs); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getExternalDocs().getDescription()).isEqualTo(externalDocs.getDescription()); - assertThat(componentSchema.getExternalDocs().getUrl()).isEqualTo(externalDocs.getUrl()); + assertThat(componentSchema.getSchema().getExternalDocs().getDescription()) + .isEqualTo(externalDocs.getDescription()); + assertThat(componentSchema.getSchema().getExternalDocs().getUrl()).isEqualTo(externalDocs.getUrl()); } @Test @@ -79,10 +169,10 @@ void mapDeprecated() { schema.setDeprecated(true); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getDeprecated()).isEqualTo(true); + assertThat(componentSchema.getSchema().getDeprecated()).isEqualTo(true); } @Test @@ -92,10 +182,10 @@ void mapTitle() { schema.setTitle("title"); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getTitle()).isEqualTo(schema.getTitle()); + assertThat(componentSchema.getSchema().getTitle()).isEqualTo(schema.getTitle()); } @Test @@ -105,10 +195,10 @@ void mapType() { schema.setType(SchemaType.STRING); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getType()).containsExactly(schema.getType()); + assertThat(componentSchema.getSchema().getType()).containsExactly(schema.getType()); } @Test @@ -120,10 +210,11 @@ void mapProperties() { schema.addProperty("property", property); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(((ComponentSchema) componentSchema.getProperties().get("property")) + assertThat(((ComponentSchema) + componentSchema.getSchema().getProperties().get("property")) .getSchema() .getType()) .containsExactly(property.getType()); @@ -136,10 +227,10 @@ void mapDescription() { schema.setDescription("description"); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getDescription()).isEqualTo(schema.getDescription()); + assertThat(componentSchema.getSchema().getDescription()).isEqualTo(schema.getDescription()); } @Test @@ -149,10 +240,10 @@ void mapFormat() { schema.setFormat("format"); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getFormat()).isEqualTo(schema.getFormat()); + assertThat(componentSchema.getSchema().getFormat()).isEqualTo(schema.getFormat()); } @Test @@ -162,10 +253,10 @@ void mapPattern() { schema.setPattern("pattern"); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getPattern()).isEqualTo(schema.getPattern()); + assertThat(componentSchema.getSchema().getPattern()).isEqualTo(schema.getPattern()); } @Test @@ -176,11 +267,11 @@ void mapExclusiveMinimum() { schema.setExclusiveMinimum(true); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getExclusiveMinimum()).isEqualTo(schema.getMinimum()); - assertThat(componentSchema.getMinimum()).isNull(); + assertThat(componentSchema.getSchema().getExclusiveMinimum()).isEqualTo(schema.getMinimum()); + assertThat(componentSchema.getSchema().getMinimum()).isNull(); } @Test @@ -190,11 +281,11 @@ void mapExclusiveMinimumValue() { schema.setExclusiveMinimumValue(BigDecimal.ONE); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getExclusiveMinimum()).isEqualTo(schema.getExclusiveMinimumValue()); - assertThat(componentSchema.getMinimum()).isNull(); + assertThat(componentSchema.getSchema().getExclusiveMinimum()).isEqualTo(schema.getExclusiveMinimumValue()); + assertThat(componentSchema.getSchema().getMinimum()).isNull(); } @Test @@ -205,11 +296,11 @@ void mapExclusiveMaximum() { schema.setExclusiveMaximum(true); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getExclusiveMaximum()).isEqualTo(schema.getMaximum()); - assertThat(componentSchema.getMaximum()).isNull(); + assertThat(componentSchema.getSchema().getExclusiveMaximum()).isEqualTo(schema.getMaximum()); + assertThat(componentSchema.getSchema().getMaximum()).isNull(); } @Test @@ -219,11 +310,11 @@ void mapExclusiveMaximumValue() { schema.setExclusiveMaximumValue(BigDecimal.ONE); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getExclusiveMaximum()).isEqualTo(schema.getExclusiveMaximumValue()); - assertThat(componentSchema.getMaximum()).isNull(); + assertThat(componentSchema.getSchema().getExclusiveMaximum()).isEqualTo(schema.getExclusiveMaximumValue()); + assertThat(componentSchema.getSchema().getMaximum()).isNull(); } @Test @@ -233,11 +324,11 @@ void mapMinimum() { schema.setMinimum(BigDecimal.ONE); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getMinimum()).isEqualTo(schema.getMinimum()); - assertThat(componentSchema.getExclusiveMinimum()).isNull(); + assertThat(componentSchema.getSchema().getMinimum()).isEqualTo(schema.getMinimum()); + assertThat(componentSchema.getSchema().getExclusiveMinimum()).isNull(); } @Test @@ -247,11 +338,11 @@ void mapMaximum() { schema.setMaximum(BigDecimal.ONE); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getMaximum()).isEqualTo(schema.getMaximum()); - assertThat(componentSchema.getExclusiveMaximum()).isNull(); + assertThat(componentSchema.getSchema().getMaximum()).isEqualTo(schema.getMaximum()); + assertThat(componentSchema.getSchema().getExclusiveMaximum()).isNull(); } @Test @@ -261,10 +352,10 @@ void mapMultipleOf() { schema.setMultipleOf(BigDecimal.ONE); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getMultipleOf()).isEqualTo(schema.getMultipleOf()); + assertThat(componentSchema.getSchema().getMultipleOf()).isEqualTo(schema.getMultipleOf()); } @Test @@ -274,10 +365,10 @@ void mapMinLength() { schema.setMinLength(1); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getMinLength()).isEqualTo(schema.getMinLength()); + assertThat(componentSchema.getSchema().getMinLength()).isEqualTo(schema.getMinLength()); } @Test @@ -287,10 +378,10 @@ void mapMaxLength() { schema.setMaxLength(1); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getMaxLength()).isEqualTo(schema.getMaxLength()); + assertThat(componentSchema.getSchema().getMaxLength()).isEqualTo(schema.getMaxLength()); } @Test @@ -300,10 +391,10 @@ void mapEnum() { schema.setEnum(List.of("enum1", "enum2")); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getEnumValues()).isEqualTo(schema.getEnum()); + assertThat(componentSchema.getSchema().getEnumValues()).isEqualTo(schema.getEnum()); } @Test @@ -313,10 +404,10 @@ void mapExample() { schema.setExample("example"); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getExamples()).isEqualTo(List.of(schema.getExample())); + assertThat(componentSchema.getSchema().getExamples()).isEqualTo(List.of(schema.getExample())); } @Test @@ -328,10 +419,14 @@ void mapAdditionalProperties() { schema.setAdditionalProperties(additionalProperties); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getAdditionalProperties().getSchema().getType()) + assertThat(componentSchema + .getSchema() + .getAdditionalProperties() + .getSchema() + .getType()) .containsExactly(additionalProperties.getType()); } @@ -342,10 +437,10 @@ void mapRequired() { schema.setRequired(List.of("required")); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getRequired()).isEqualTo(schema.getRequired()); + assertThat(componentSchema.getSchema().getRequired()).isEqualTo(schema.getRequired()); } @Test @@ -357,10 +452,13 @@ void mapDiscriminator() { schema.setDiscriminator(discriminator); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getDiscriminator()).isEqualTo("name"); + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + + assertThat(componentSchema.getSchema().getDiscriminator()).isEqualTo("name"); } @Test @@ -372,10 +470,13 @@ void mapAllOf() { schema.addAllOfItem(allOf); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat((componentSchema.getAllOf().get(0).getSchema()).getType()) + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + + assertThat((componentSchema.getSchema().getAllOf().get(0).getSchema()).getType()) .containsExactly(allOf.getType()); } @@ -388,10 +489,13 @@ void mapOneOf() { schema.addOneOfItem(oneOf); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat((componentSchema.getOneOf().get(0).getSchema()).getType()) + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + + assertThat((componentSchema.getSchema().getOneOf().get(0).getSchema()).getType()) .containsExactly(oneOf.getType()); } @@ -404,10 +508,12 @@ void mapAnyOf() { schema.addAnyOfItem(anyOf); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat((componentSchema.getAnyOf().get(0).getSchema()).getType()) + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + assertThat((componentSchema.getSchema().getAnyOf().get(0).getSchema()).getType()) .containsExactly(anyOf.getType()); } @@ -418,10 +524,12 @@ void mapConst() { schema.setConst("const"); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getConstValue()).isEqualTo(schema.getConst()); + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + assertThat(componentSchema.getSchema().getConstValue()).isEqualTo(schema.getConst()); } @Test @@ -433,10 +541,13 @@ void mapNot() { schema.setNot(not); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat((componentSchema.getNot().getSchema()).getType()).containsExactly(not.getType()); + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + assertThat((componentSchema.getSchema().getNot().getSchema()).getType()) + .containsExactly(not.getType()); } @Test @@ -449,10 +560,13 @@ void mapItems() { schema.setItems(item); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat((componentSchema.getItems().getSchema()).getType()).containsExactly(item.getType()); + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + assertThat((componentSchema.getSchema().getItems().getSchema()).getType()) + .containsExactly(item.getType()); } @Test @@ -462,10 +576,12 @@ void mapUniqueItems() { schema.setUniqueItems(false); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getUniqueItems()).isEqualTo(schema.getUniqueItems()); + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + assertThat(componentSchema.getSchema().getUniqueItems()).isEqualTo(schema.getUniqueItems()); } @Test @@ -475,10 +591,12 @@ void mapMinItems() { schema.setMinItems(1); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getMinItems()).isEqualTo(schema.getMinItems()); + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + assertThat(componentSchema.getSchema().getMinItems()).isEqualTo(schema.getMinItems()); } @Test @@ -488,10 +606,12 @@ void mapMaxItems() { schema.setMaxItems(10); // when - SchemaObject componentSchema = swaggerSchemaUtil.mapSchema(schema); + ComponentSchema componentSchema = swaggerSchemaUtil.mapSchema(schema, PayloadSchemaFormat.ASYNCAPI_V3); // then - assertThat(componentSchema.getMaxItems()).isEqualTo(schema.getMaxItems()); + // ensure that componentSchema contains an AsnycApi SchemaObjekt. + assertThat(componentSchema.getSchema()).isNotNull(); + assertThat(componentSchema.getSchema().getMaxItems()).isEqualTo(schema.getMaxItems()); } } @@ -504,10 +624,10 @@ void mapDescription() { schema.setDescription("description"); // when - Schema componentSchema = swaggerSchemaUtil.mapToSwagger(schema); + Schema swaggerSchema = swaggerSchemaUtil.mapToSwagger(schema); // then - assertThat(componentSchema.getDescription()).isEqualTo(schema.getDescription()); + assertThat(swaggerSchema.getDescription()).isEqualTo(schema.getDescription()); } @Test @@ -517,10 +637,10 @@ void mapExamples() { schema.setExamples(List.of("example1", "example2")); // when - Schema componentSchema = swaggerSchemaUtil.mapToSwagger(schema); + Schema swaggerSchema = swaggerSchemaUtil.mapToSwagger(schema); // then - assertThat(componentSchema.getExamples()).isEqualTo(schema.getExamples()); + assertThat(swaggerSchema.getExamples()).isEqualTo(schema.getExamples()); } @Test @@ -530,10 +650,10 @@ void mapEnum() { schema.setEnumValues(List.of("enum1", "enum2")); // when - Schema componentSchema = swaggerSchemaUtil.mapToSwagger(schema); + Schema swaggerSchema = swaggerSchemaUtil.mapToSwagger(schema); // then - assertThat(componentSchema.getEnum()).isEqualTo(schema.getEnumValues()); + assertThat(swaggerSchema.getEnum()).isEqualTo(schema.getEnumValues()); } @Test @@ -544,11 +664,11 @@ void mapNullableEnum() { schema.setTypes(Set.of(SchemaType.STRING, SchemaType.NULL)); // nullable // when - Schema componentSchema = swaggerSchemaUtil.mapToSwagger(schema); + Schema swaggerSchema = swaggerSchemaUtil.mapToSwagger(schema); // then - assertThat(componentSchema.getEnum()).isEqualTo(schema.getEnumValues()); - assertThat(componentSchema.getTypes()).isEqualTo(schema.getType()); + assertThat(swaggerSchema.getEnum()).isEqualTo(schema.getEnumValues()); + assertThat(swaggerSchema.getTypes()).isEqualTo(schema.getType()); } @Test @@ -558,10 +678,10 @@ void mapType() { schema.setType(SchemaType.STRING); // when - Schema componentSchema = swaggerSchemaUtil.mapToSwagger(schema); + Schema swaggerSchema = swaggerSchemaUtil.mapToSwagger(schema); // then - assertThat(componentSchema.getType()).isEqualTo(SchemaType.STRING); + assertThat(swaggerSchema.getType()).isEqualTo(SchemaType.STRING); } } } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalkerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalkerTest.java new file mode 100644 index 000000000..fc7b9c215 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalkerTest.java @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.components.examples.walkers; + +import io.swagger.v3.oas.models.media.Schema; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class DefaultSchemaWalkerTest { + + @Test + void getTypeForExampleValue() { + DefaultSchemaWalker schemaWalker = new DefaultSchemaWalker<>(null); + + Schema schema1 = new Schema(); // no types defined. + Schema schema2 = new Schema().type("string"); + Schema schema3 = new Schema().types(Set.of("string", "null")); + Schema schema4 = new Schema().types(Set.of("string", "integer")); + + assertThat(schemaWalker.getTypeForExampleValue(schema1)).isNull(); + assertThat(schemaWalker.getTypeForExampleValue(schema2)).isEqualTo("string"); + assertThat(schemaWalker.getTypeForExampleValue(schema3)).isEqualTo("string"); + assertThat(schemaWalker.getTypeForExampleValue(schema4)).isEqualTo("integer"); + } +} 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 e80ad1ace..5c7b369fe 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 @@ -29,6 +29,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeExtractor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; @@ -71,6 +72,7 @@ SchemaWalkerProvider.class, ExampleJsonValueGenerator.class, SpringwolfConfigProperties.class, + ModelConvertersProvider.class }) class SpringAnnotationClassLevelChannelsScannerIntegrationTest { diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java index f95a6a4e1..92b6da7a4 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java @@ -29,6 +29,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeExtractor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; @@ -73,6 +74,7 @@ SchemaWalkerProvider.class, ExampleJsonValueGenerator.class, SpringwolfConfigProperties.class, + ModelConvertersProvider.class }) class SpringAnnotationMethodLevelChannelsScannerIntegrationTest { @Autowired diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorIntegrationTest.java index 3be2f7650..329deff50 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorIntegrationTest.java @@ -5,6 +5,7 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; @@ -12,7 +13,6 @@ import io.swagger.v3.core.converter.ModelConverters; import lombok.val; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.messaging.handler.annotation.Header; @@ -25,8 +25,13 @@ class HeaderClassExtractorIntegrationTest { - private final SwaggerSchemaService schemaService = - new SwaggerSchemaService(List.of(), List.of(), new SwaggerSchemaUtil(), new SpringwolfConfigProperties()); + private static final SchemaTitleModelConverter titleModelConverter = new SchemaTitleModelConverter(); + + private final SwaggerSchemaService schemaService = new SwaggerSchemaService( + List.of(), + new SwaggerSchemaUtil(), + new SpringwolfConfigProperties(), + new ModelConvertersProvider(List.of(titleModelConverter))); private final HeaderClassExtractor headerClassExtractor = new HeaderClassExtractor(schemaService); private final PayloadSchemaObject payloadSchemaName = new PayloadSchemaObject( @@ -34,15 +39,6 @@ class HeaderClassExtractorIntegrationTest { private final SchemaObject stringSchema = SchemaObject.builder().type(SchemaType.STRING).build(); - private static final SchemaTitleModelConverter titleModelConverter = new SchemaTitleModelConverter(); - - @BeforeAll - static void setupClass() { - // make sure hat SpringWolf SchemaTitleModelConverter is registered with ModelConverters static registry. - // this happens in Spring tests automatically but to run only this testclass, this is necessary: - ModelConverters.getInstance().addConverter(titleModelConverter); - } - @AfterAll static void tearDownClass() { ModelConverters.getInstance().removeConverter(titleModelConverter); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java index 5560d7b09..d1ad408b0 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java @@ -51,7 +51,7 @@ static void tearDownClass() { @Test void getNoDocumentedHeaders() throws Exception { // given - when(schemaService.extractSchema(String.class)) + when(schemaService.postProcessSimpleSchema(String.class)) .thenReturn(new SwaggerSchemaService.ExtractedSchemas(stringSwaggerSchema, Map.of())); // when @@ -65,7 +65,7 @@ void getNoDocumentedHeaders() throws Exception { @Test void getHeaderWithSingleHeaderAnnotation() throws Exception { // given - when(schemaService.extractSchema(String.class)) + when(schemaService.postProcessSimpleSchema(String.class)) .thenReturn(new SwaggerSchemaService.ExtractedSchemas(stringSwaggerSchema, Map.of())); // when @@ -86,7 +86,7 @@ void getHeaderWithSingleHeaderAnnotation() throws Exception { @Test void getHeaderWithMultipleHeaderAnnotation() throws Exception { // given - when(schemaService.extractSchema(String.class)) + when(schemaService.postProcessSimpleSchema(String.class)) .thenReturn(new SwaggerSchemaService.ExtractedSchemas(stringSwaggerSchema, Map.of())); // when diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java index 6cc062bdb..7c5a73b7f 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java @@ -8,8 +8,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaFormat; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.components.postprocessors.SchemasPostProcessor; +import io.github.springwolf.core.configuration.properties.PayloadSchemaFormat; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import io.swagger.v3.core.converter.AnnotatedType; import io.swagger.v3.core.converter.ModelConverter; @@ -48,28 +50,56 @@ class SwaggerSchemaServiceTest { @BeforeEach void setUp() { schemaService = new SwaggerSchemaService( - List.of(new ModelConverterNativeClass.Converter()), List.of(schemasPostProcessor, schemasPostProcessor2), new SwaggerSchemaUtil(), - new SpringwolfConfigProperties()); + new SpringwolfConfigProperties(), + new ModelConvertersProvider(List.of(new ModelConverterNativeClass.Converter()))); } @Test void classWithSchemaAnnotationWithAsyncapiSchemaformat() { - ComponentSchema schema = schemaService - .resolveSchema(ClassWithSchemaAnnotation.class, "content-type-not-relevant") - .rootSchema(); + SwaggerSchemaService.ExtractedSchemas extractedSchemas = schemaService.resolveSchema( + ClassWithSchemaAnnotation.class, "content-type-not-relevant", PayloadSchemaFormat.ASYNCAPI_V3); - assertThat(schema.getReference().getRef()).isEqualTo("#/components/schemas/DifferentName"); + assertThat(extractedSchemas.referencedSchemas()).hasSize(1); + ComponentSchema modelSchema = extractedSchemas.referencedSchemas().get("DifferentName"); + assertThat(modelSchema.getSchema()).isNotNull(); // we expect an asyncapi schema + assertThat(modelSchema.getMultiFormatSchema()).isNull(); + + ComponentSchema rootSchema = extractedSchemas.rootSchema(); + assertThat(rootSchema.getReference().getRef()).isEqualTo("#/components/schemas/DifferentName"); } @Test - void classWithSchemaAnnotationWithOpenapiSchemaformat() { - ComponentSchema schema = schemaService - .resolveSchema(ClassWithSchemaAnnotation.class, "content-type-not-relevant") - .rootSchema(); + void classWithSchemaAnnotationWithOpenapiSchema30format() { + SwaggerSchemaService.ExtractedSchemas extractedSchemas = schemaService.resolveSchema( + ClassWithSchemaAnnotation.class, "content-type-not-relevant", PayloadSchemaFormat.OPENAPI_V3); + + assertThat(extractedSchemas.referencedSchemas()).hasSize(1); + ComponentSchema modelSchema = extractedSchemas.referencedSchemas().get("DifferentName"); + // we expect modelSchema to contain a multiformat schema with schemaformat openapi-v3 + assertThat(modelSchema.getMultiFormatSchema()).isNotNull(); + assertThat(modelSchema.getMultiFormatSchema().getSchemaFormat()).isEqualTo(SchemaFormat.OPENAPI_V3.value); + assertThat(modelSchema.getSchema()).isNull(); + + ComponentSchema rootSchema = extractedSchemas.rootSchema(); + assertThat(rootSchema.getReference().getRef()).isEqualTo("#/components/schemas/DifferentName"); + } - assertThat(schema.getReference().getRef()).isEqualTo("#/components/schemas/DifferentName"); + @Test + void classWithSchemaAnnotationWithOpenapiSchema31format() { + SwaggerSchemaService.ExtractedSchemas extractedSchemas = schemaService.resolveSchema( + ClassWithSchemaAnnotation.class, "content-type-not-relevant", PayloadSchemaFormat.OPENAPI_V3_1); + + assertThat(extractedSchemas.referencedSchemas()).hasSize(1); + ComponentSchema modelSchema = extractedSchemas.referencedSchemas().get("DifferentName"); + // we expect modelSchema to contain a multiformat schema with schemaformat openapi-v3.1 + assertThat(modelSchema.getMultiFormatSchema()).isNotNull(); + assertThat(modelSchema.getMultiFormatSchema().getSchemaFormat()).isEqualTo(SchemaFormat.OPENAPI_V3_1.value); + assertThat(modelSchema.getSchema()).isNull(); + + ComponentSchema rootSchema = extractedSchemas.rootSchema(); + assertThat(rootSchema.getReference().getRef()).isEqualTo("#/components/schemas/DifferentName"); } @Test @@ -78,14 +108,14 @@ void getDefinitionWithoutFqnClassName() throws Exception { SpringwolfConfigProperties properties = new SpringwolfConfigProperties(); properties.setUseFqn(false); - SwaggerSchemaService schemaServiceWithFqn = - new SwaggerSchemaService(List.of(), List.of(), new SwaggerSchemaUtil(), properties); + SwaggerSchemaService schemaServiceWithFqn = new SwaggerSchemaService( + List.of(), new SwaggerSchemaUtil(), properties, new ModelConvertersProvider(List.of())); // when Class clazz = OneFieldFooWithoutFqn.class; // swagger seems to cache results. Therefore, a new class must be used. Map schemas = schemaServiceWithFqn - .resolveSchema(clazz, "content-type-not-relevant") + .resolveSchema(clazz, "content-type-not-relevant", PayloadSchemaFormat.ASYNCAPI_V3) .referencedSchemas(); String actualDefinitions = objectMapper.writer(printer).writeValueAsString(schemas); @@ -97,7 +127,8 @@ void getDefinitionWithoutFqnClassName() throws Exception { @Test void postProcessorsAreCalledWithAsyncapiSchemaformat() { - schemaService.resolveSchema(ClassWithSchemaAnnotation.class, "some-content-type"); + schemaService.resolveSchema( + ClassWithSchemaAnnotation.class, "some-content-type", PayloadSchemaFormat.ASYNCAPI_V3); verify(schemasPostProcessor).process(any(), any(), eq("some-content-type")); verify(schemasPostProcessor2).process(any(), any(), eq("some-content-type")); @@ -105,7 +136,8 @@ void postProcessorsAreCalledWithAsyncapiSchemaformat() { @Test void postProcessorsAreCalledWithOpenapiSchemaformat() { - schemaService.resolveSchema(ClassWithSchemaAnnotation.class, "some-content-type"); + schemaService.resolveSchema( + ClassWithSchemaAnnotation.class, "some-content-type", PayloadSchemaFormat.OPENAPI_V3); verify(schemasPostProcessor).process(any(), any(), eq("some-content-type")); verify(schemasPostProcessor2).process(any(), any(), eq("some-content-type")); @@ -121,15 +153,16 @@ void postProcessorIsSkippedWhenSchemaWasRemoved() { .when(schemasPostProcessor) .process(any(), any(), any()); - schemaService.resolveSchema(ClassWithSchemaAnnotation.class, "content-type-not-relevant"); + schemaService.resolveSchema( + ClassWithSchemaAnnotation.class, "content-type-not-relevant", PayloadSchemaFormat.ASYNCAPI_V3); verifyNoInteractions(schemasPostProcessor2); } @Test void modelConvertersRefsAreResolved() { - SwaggerSchemaService.ExtractedSchemas schema = - schemaService.resolveSchema(ModelConverterNativeClass.class, "content-type-not-relevant"); + SwaggerSchemaService.ExtractedSchemas schema = schemaService.resolveSchema( + ModelConverterNativeClass.class, "content-type-not-relevant", PayloadSchemaFormat.ASYNCAPI_V3); assertThat(schema.rootSchema().getReference().getRef()) .contains(ModelConverterNativeClass.class.getName().replace("$", ".")); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentWithOpenApiV31SchemaFormatIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentWithOpenApiV31SchemaFormatIntegrationTest.java new file mode 100644 index 000000000..e43d81004 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentWithOpenApiV31SchemaFormatIntegrationTest.java @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.integrationtests; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.github.springwolf.asyncapi.v3.jackson.AsyncApiSerializerService; +import io.github.springwolf.asyncapi.v3.model.AsyncAPI; +import io.github.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaFormat; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; +import io.github.springwolf.core.asyncapi.AsyncApiService; +import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; +import io.github.springwolf.core.fixtures.MinimalIntegrationTestContextConfiguration; +import io.github.springwolf.core.integrationtests.application.fqn.FqnApplication; +import io.github.springwolf.core.integrationtests.application.listener.ListenerApplication; +import io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication; +import io.github.springwolf.core.integrationtests.application.publisher.PublisherApplication; +import io.github.springwolf.core.integrationtests.application.schema.SchemaEnumAsRefApplication; +import io.github.springwolf.core.standalone.DefaultStandaloneApplication; +import io.swagger.v3.oas.models.media.Schema; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.test.context.TestPropertySource; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AsyncApiDocumentWithOpenApiV31SchemaFormatIntegrationTest { + + @Nested + @SpringBootTest(classes = ListenerApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.listener", + "springwolf.docket.payload-schema-format=openapi_v3_1" + }) + class ListenerAnnotationTest { + @Value("${springwolf.docket.base-package}") + private String basePackage; + + @Autowired + private ConfigurableEnvironment environment; + + @Autowired + private AsyncApiService asyncApiService; + + @Test + void asyncListenerAnnotationIsFound() { + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + assertThat(asyncAPI).isNotNull(); + + assertThat(asyncAPI.getChannels().keySet()) + .containsExactlyInAnyOrder("listener-channel", "listener-class-channel"); + assertThat(asyncAPI.getChannels().get("listener-channel").getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getChannels().get("listener-class-channel").getMessages()) + .containsOnlyKeys("java.lang.Integer"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys( + "listener-channel_receive_listen", + "listener-channel_receive_listen2", + "listener-channel_receive_listen3", + "listener-channel_receive_listen4", + "listener-class-channel_receive_listen"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getComponents().getSchemas()) + .containsOnlyKeys( + "HeadersNotDocumented", + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + + MessageObject stringMessage = + (MessageObject) asyncAPI.getComponents().getMessages().get("java.lang.String"); + assertThat(stringMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(Schema.class); + Schema inlineStringSchema = + (Schema) stringMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(inlineStringSchema.getTypes()).containsExactly("string"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaReference.class); + SchemaReference fooSchemaRef = (SchemaReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooSchemaRef.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + } + + @Test + void ensureThatStandaloneResultIsIdentical() { + // given + AsyncApiService asyncApiService = createStandaloneAsyncApiService(environment, basePackage); + + // when + AsyncAPI asyncApi = asyncApiService.getAsyncAPI(); + + // then + assertThat(asyncApi).isEqualTo(asyncApiService.getAsyncAPI()); + } + } + + @Nested + @SpringBootTest(classes = PublisherApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.publisher", + "springwolf.docket.payload-schema-format=openapi_v3_1" + }) + class PublisherAnnotationTest { + @Value("${springwolf.docket.base-package}") + private String basePackage; + + @Autowired + private ConfigurableEnvironment environment; + + @Autowired + private AsyncApiService asyncApiService; + + @Test + void asyncPublisherAnnotationIsFound() { + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + assertThat(asyncAPI).isNotNull(); + + assertThat(asyncAPI.getChannels().keySet()) + .containsExactlyInAnyOrder("publisher-channel", "publisher-class-channel"); + assertThat(asyncAPI.getChannels().get("publisher-channel").getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getChannels().get("publisher-class-channel").getMessages()) + .containsOnlyKeys("java.lang.Integer"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys( + "publisher-channel_send_publish", + "publisher-channel_send_publish2", + "publisher-channel_send_publish3", + "publisher-channel_send_publish4", + "publisher-class-channel_send_publish"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getComponents().getSchemas()) + .containsOnlyKeys( + "HeadersNotDocumented", + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + + MessageObject stringMessage = + (MessageObject) asyncAPI.getComponents().getMessages().get("java.lang.String"); + assertThat(stringMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(Schema.class); // Swagger Schema + + Schema inlineStringSchema = + (Schema) stringMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(inlineStringSchema.getTypes()).containsExactly("string"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaReference.class); + SchemaReference fooSchemaRef = (SchemaReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooSchemaRef.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + } + + @Test + void ensureThatStandaloneResultIsIdentical() { + // given + AsyncApiService asyncApiService = createStandaloneAsyncApiService(environment, basePackage); + + // when + AsyncAPI asyncApi = asyncApiService.getAsyncAPI(); + + // then + assertThat(asyncApi).isEqualTo(asyncApiService.getAsyncAPI()); + } + } + + @Nested + @SpringBootTest(classes = FqnApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.fqn", + "springwolf.use-fqn=false", + "springwolf.docket.payload-schema-format=openapi_v3_1" + }) + class FqnTest { + @Autowired + private AsyncApiService asyncApiService; + + @Autowired + private AsyncApiSerializerService asyncApiSerializerService; + + @Test + void allClassesHaveSimpleNameNotFullQualifiedTest() throws Exception { + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + assertThat(asyncAPI).isNotNull(); + String serialized = asyncApiSerializerService.toJsonString(asyncAPI); + + assertThat(serialized) + .contains( + "string", + "integer", + FqnApplication.Foo.class.getSimpleName(), + FqnApplication.Bar.class.getSimpleName(), + AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) + .doesNotContain( + String.class.getName(), + Integer.class.getName(), + FqnApplication.Foo.class.getName(), + FqnApplication.Bar.class.getName()); + } + } + + @Nested + @SpringBootTest(classes = PolymorphicPayloadApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.polymorphic", + "springwolf.docket.payload-schema-format=openapi_v3_1" + }) + class PolymorphicPayloadTest { + @Autowired + private AsyncApiService asyncApiService; + + @Test + void polymorphicDiscriminatorFieldIsHandled() throws JsonProcessingException { + // when + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + // + // System.out.println(Json.mapper().writerWithDefaultPrettyPrinter().writeValueAsString(asyncAPI)); + + // then + Map messages = asyncAPI.getComponents().getMessages(); + assertThat(messages) + .containsOnlyKeys( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Payload"); + Map schemas = asyncAPI.getComponents().getSchemas(); + assertThat(schemas) + .containsOnlyKeys( + "HeadersNotDocumented", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Payload", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Cat", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Dog"); + + Schema petSchema = (Schema) schemas.get( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet") + .getMultiFormatSchema() + .getSchema(); + + assertThat(petSchema.getDiscriminator().getPropertyName()).isEqualTo("type"); + assertThat(petSchema.getDiscriminator().getMapping()) + .containsAllEntriesOf( + Map.of( + "dog", + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Dog", + "cat", + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Cat")); + + Schema catSchema = (Schema) schemas.get( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Cat") + .getMultiFormatSchema() + .getSchema(); + + assertThat(catSchema.getAllOf().get(0).get$ref()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet"); + + assertThat(catSchema.getAllOf().get(1).getProperties()).containsOnlyKeys("catSpecificField"); + + Schema dogSchema = (Schema) schemas.get( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Dog") + .getMultiFormatSchema() + .getSchema(); + + assertThat(dogSchema.getAllOf().get(0).get$ref()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet"); + assertThat(dogSchema.getAllOf().get(1).getProperties()).containsOnlyKeys("dogSpecificField"); + } + } + + @Nested + @SpringBootTest(classes = SchemaEnumAsRefApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.schema", + "springwolf.docket.payload-schema-format=openapi_v3_1" + }) + class SchemaAsRefTest { + @Autowired + private AsyncApiService asyncApiService; + + @Test + void enumAsRefIsHandled() { + // given + String myEnumRootSchemaName = + "io.github.springwolf.core.integrationtests.application.schema.SchemaEnumAsRefApplication.Schemas.MyEnumRoot"; + String myEnumObjectSchemaName = + "io.github.springwolf.core.integrationtests.application.schema.SchemaEnumAsRefApplication.Schemas.MyEnumObject"; + + // when + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + + // then + Map messages = asyncAPI.getComponents().getMessages(); + assertThat(messages).containsOnlyKeys(myEnumRootSchemaName); + Map schemas = asyncAPI.getComponents().getSchemas(); + assertThat(schemas).containsOnlyKeys("HeadersNotDocumented", myEnumRootSchemaName, myEnumObjectSchemaName); + + assertThat(schemas.get(myEnumRootSchemaName).getMultiFormatSchema().getSchemaFormat()) + .isEqualTo(SchemaFormat.OPENAPI_V3_1.value); + Schema openapiSchema1 = (Schema) + schemas.get(myEnumRootSchemaName).getMultiFormatSchema().getSchema(); + + assertThat(openapiSchema1.getExample().toString()).isEqualTo("{\"myEnumObjectField\":\"DOG\"}"); + + assertThat(schemas.get(myEnumObjectSchemaName) + .getMultiFormatSchema() + .getSchemaFormat()) + .isEqualTo(SchemaFormat.OPENAPI_V3_1.value); + Schema openapiSchema2 = (Schema) + schemas.get(myEnumObjectSchemaName).getMultiFormatSchema().getSchema(); + + assertThat(openapiSchema2.getExample().toString()).isEqualTo("\"DOG\""); + } + } + + @Nested + @SpringBootTest(classes = ListenerApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.listener", + "springwolf.docket.payload-schema-format=openapi_v3_1", + "springwolf.docket.group-configs[0].group=FooMessage", + "springwolf.docket.group-configs[0].action-to-match=", + "springwolf.docket.group-configs[0].channel-name-to-match=", + "springwolf.docket.group-configs[0].message-name-to-match=.*Foo", + "springwolf.docket.group-configs[1].group=all & everything", + "springwolf.docket.group-configs[1].action-to-match=", + "springwolf.docket.group-configs[1].channel-name-to-match=.*", + "springwolf.docket.group-configs[1].message-name-to-match=", + }) + class GroupingTest { + @Autowired + private AsyncApiService asyncApiService; + + @Test + void shouldFindOnlyForGroupFoo() { + AsyncAPI asyncAPI = asyncApiService.getForGroupName("FooMessage").get(); + + assertThat(asyncAPI.getChannels().keySet()).containsExactlyInAnyOrder("listener-channel"); + assertThat(asyncAPI.getChannels().get("listener-channel").getMessages()) + .containsOnlyKeys( + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys("listener-channel_receive_listen3", "listener-channel_receive_listen4"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getComponents().getSchemas()) + .containsOnlyKeys( + "HeadersNotDocumented", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaReference.class); + SchemaReference fooSchemaRef = (SchemaReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooSchemaRef.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + } + + @Test + void shouldFindAllForGroupAll() { + // given + AsyncAPI fullApi = asyncApiService.getAsyncAPI(); + + // when + AsyncAPI asyncAPIOpt = + asyncApiService.getForGroupName("all & everything").get(); + + // then + + // String and Integer get filtered. + // Question: Why are they in the fullApi in the first place, if not referenced? (inline schema) + fullApi.getComponents().getSchemas().remove(String.class.getName()); + fullApi.getComponents().getSchemas().remove(Integer.class.getName()); + + assertThat(asyncAPIOpt).isEqualTo(fullApi); + } + } + + private AsyncApiService createStandaloneAsyncApiService(ConfigurableEnvironment environment, String basePackage) { + DefaultStandaloneApplication standaloneApplication = DefaultStandaloneApplication.builder() + .addScanPackage(basePackage) + .setEnvironment(environment) + .buildAndStart(); + return standaloneApplication.getAsyncApiService(); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentWithOpenApiV3SchemaFormatIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentWithOpenApiV3SchemaFormatIntegrationTest.java new file mode 100644 index 000000000..1fd522761 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentWithOpenApiV3SchemaFormatIntegrationTest.java @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.integrationtests; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.github.springwolf.asyncapi.v3.jackson.AsyncApiSerializerService; +import io.github.springwolf.asyncapi.v3.model.AsyncAPI; +import io.github.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaFormat; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; +import io.github.springwolf.core.asyncapi.AsyncApiService; +import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; +import io.github.springwolf.core.fixtures.MinimalIntegrationTestContextConfiguration; +import io.github.springwolf.core.integrationtests.application.fqn.FqnApplication; +import io.github.springwolf.core.integrationtests.application.listener.ListenerApplication; +import io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication; +import io.github.springwolf.core.integrationtests.application.publisher.PublisherApplication; +import io.github.springwolf.core.integrationtests.application.schema.SchemaEnumAsRefApplication; +import io.github.springwolf.core.standalone.DefaultStandaloneApplication; +import io.swagger.v3.oas.models.media.Schema; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.test.context.TestPropertySource; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AsyncApiDocumentWithOpenApiV3SchemaFormatIntegrationTest { + + @Nested + @SpringBootTest(classes = ListenerApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.listener", + "springwolf.docket.payload-schema-format=openapi_v3" + }) + class ListenerAnnotationTest { + @Value("${springwolf.docket.base-package}") + private String basePackage; + + @Autowired + private ConfigurableEnvironment environment; + + @Autowired + private AsyncApiService asyncApiService; + + @Test + void asyncListenerAnnotationIsFound() { + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + assertThat(asyncAPI).isNotNull(); + + assertThat(asyncAPI.getChannels().keySet()) + .containsExactlyInAnyOrder("listener-channel", "listener-class-channel"); + assertThat(asyncAPI.getChannels().get("listener-channel").getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getChannels().get("listener-class-channel").getMessages()) + .containsOnlyKeys("java.lang.Integer"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys( + "listener-channel_receive_listen", + "listener-channel_receive_listen2", + "listener-channel_receive_listen3", + "listener-channel_receive_listen4", + "listener-class-channel_receive_listen"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getComponents().getSchemas()) + .containsOnlyKeys( + "HeadersNotDocumented", + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + + MessageObject stringMessage = + (MessageObject) asyncAPI.getComponents().getMessages().get("java.lang.String"); + assertThat(stringMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(Schema.class); + Schema inlineStringSchema = + (Schema) stringMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(inlineStringSchema.getType()).isEqualTo("string"); + assertThat(inlineStringSchema.getTypes()).containsExactly("string"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaReference.class); + SchemaReference fooSchemaRef = (SchemaReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooSchemaRef.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + } + + @Test + void ensureThatStandaloneResultIsIdentical() { + // given + AsyncApiService asyncApiService = createStandaloneAsyncApiService(environment, basePackage); + + // when + AsyncAPI asyncApi = asyncApiService.getAsyncAPI(); + + // then + assertThat(asyncApi).isEqualTo(asyncApiService.getAsyncAPI()); + } + } + + @Nested + @SpringBootTest(classes = PublisherApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.publisher", + "springwolf.docket.payload-schema-format=openapi_v3" + }) + class PublisherAnnotationTest { + @Value("${springwolf.docket.base-package}") + private String basePackage; + + @Autowired + private ConfigurableEnvironment environment; + + @Autowired + private AsyncApiService asyncApiService; + + @Test + void asyncPublisherAnnotationIsFound() { + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + assertThat(asyncAPI).isNotNull(); + + assertThat(asyncAPI.getChannels().keySet()) + .containsExactlyInAnyOrder("publisher-channel", "publisher-class-channel"); + assertThat(asyncAPI.getChannels().get("publisher-channel").getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getChannels().get("publisher-class-channel").getMessages()) + .containsOnlyKeys("java.lang.Integer"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys( + "publisher-channel_send_publish", + "publisher-channel_send_publish2", + "publisher-channel_send_publish3", + "publisher-channel_send_publish4", + "publisher-class-channel_send_publish"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getComponents().getSchemas()) + .containsOnlyKeys( + "HeadersNotDocumented", + "java.lang.String", + "java.lang.Integer", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + + MessageObject stringMessage = + (MessageObject) asyncAPI.getComponents().getMessages().get("java.lang.String"); + assertThat(stringMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(Schema.class); // Swagger Schema + + Schema inlineStringSchema = + (Schema) stringMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(inlineStringSchema.getType()).isEqualTo("string"); + assertThat(inlineStringSchema.getTypes()).containsExactly("string"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaReference.class); + SchemaReference fooSchemaRef = (SchemaReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooSchemaRef.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + } + + @Test + void ensureThatStandaloneResultIsIdentical() { + // given + AsyncApiService asyncApiService = createStandaloneAsyncApiService(environment, basePackage); + + // when + AsyncAPI asyncApi = asyncApiService.getAsyncAPI(); + + // then + assertThat(asyncApi).isEqualTo(asyncApiService.getAsyncAPI()); + } + } + + @Nested + @SpringBootTest(classes = FqnApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.fqn", + "springwolf.use-fqn=false", + "springwolf.docket.payload-schema-format=openapi_v3" + }) + class FqnTest { + @Autowired + private AsyncApiService asyncApiService; + + @Autowired + private AsyncApiSerializerService asyncApiSerializerService; + + @Test + void allClassesHaveSimpleNameNotFullQualifiedTest() throws Exception { + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + assertThat(asyncAPI).isNotNull(); + String serialized = asyncApiSerializerService.toJsonString(asyncAPI); + + assertThat(serialized) + .contains( + "string", + "integer", + FqnApplication.Foo.class.getSimpleName(), + FqnApplication.Bar.class.getSimpleName(), + AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) + .doesNotContain( + String.class.getName(), + Integer.class.getName(), + FqnApplication.Foo.class.getName(), + FqnApplication.Bar.class.getName()); + } + } + + @Nested + @SpringBootTest(classes = PolymorphicPayloadApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.polymorphic", + "springwolf.docket.payload-schema-format=openapi_v3" + }) + class PolymorphicPayloadTest { + @Autowired + private AsyncApiService asyncApiService; + + @Test + void polymorphicDiscriminatorFieldIsHandled() throws JsonProcessingException { + // when + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + + // then + Map messages = asyncAPI.getComponents().getMessages(); + assertThat(messages) + .containsOnlyKeys( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Payload"); + Map schemas = asyncAPI.getComponents().getSchemas(); + assertThat(schemas) + .containsOnlyKeys( + "HeadersNotDocumented", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Payload", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Cat", + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Dog"); + + Schema petSchema = (Schema) schemas.get( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet") + .getMultiFormatSchema() + .getSchema(); + + assertThat(petSchema.getDiscriminator().getPropertyName()).isEqualTo("type"); + assertThat(petSchema.getDiscriminator().getMapping()) + .containsAllEntriesOf( + Map.of( + "dog", + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Dog", + "cat", + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Cat")); + + Schema catSchema = (Schema) schemas.get( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Cat") + .getMultiFormatSchema() + .getSchema(); + + assertThat(catSchema.getAllOf().get(0).get$ref()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet"); + + assertThat(catSchema.getAllOf().get(1).getProperties()).containsOnlyKeys("catSpecificField"); + + Schema dogSchema = (Schema) schemas.get( + "io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Dog") + .getMultiFormatSchema() + .getSchema(); + + assertThat(dogSchema.getAllOf().get(0).get$ref()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.polymorphic.PolymorphicPayloadApplication.Pet"); + assertThat(dogSchema.getAllOf().get(1).getProperties()).containsOnlyKeys("dogSpecificField"); + } + } + + @Nested + @SpringBootTest(classes = SchemaEnumAsRefApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.schema", + "springwolf.docket.payload-schema-format=openapi_v3" + }) + class SchemaAsRefTest { + @Autowired + private AsyncApiService asyncApiService; + + @Test + void enumAsRefIsHandled() { + // given + String myEnumRootSchemaName = + "io.github.springwolf.core.integrationtests.application.schema.SchemaEnumAsRefApplication.Schemas.MyEnumRoot"; + String myEnumObjectSchemaName = + "io.github.springwolf.core.integrationtests.application.schema.SchemaEnumAsRefApplication.Schemas.MyEnumObject"; + + // when + AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); + + // then + Map messages = asyncAPI.getComponents().getMessages(); + assertThat(messages).containsOnlyKeys(myEnumRootSchemaName); + Map schemas = asyncAPI.getComponents().getSchemas(); + assertThat(schemas).containsOnlyKeys("HeadersNotDocumented", myEnumRootSchemaName, myEnumObjectSchemaName); + + assertThat(schemas.get(myEnumRootSchemaName).getMultiFormatSchema().getSchemaFormat()) + .isEqualTo(SchemaFormat.OPENAPI_V3.value); + Schema openapiSchema1 = (Schema) + schemas.get(myEnumRootSchemaName).getMultiFormatSchema().getSchema(); + + assertThat(openapiSchema1.getExample().toString()).isEqualTo("{\"myEnumObjectField\":\"\\\"DOG\\\"\"}"); + + assertThat(schemas.get(myEnumObjectSchemaName) + .getMultiFormatSchema() + .getSchemaFormat()) + .isEqualTo(SchemaFormat.OPENAPI_V3.value); + Schema openapiSchema2 = (Schema) + schemas.get(myEnumObjectSchemaName).getMultiFormatSchema().getSchema(); + + assertThat(openapiSchema2.getExample().toString()).isEqualTo("\"DOG\""); + } + } + + @Nested + @SpringBootTest(classes = ListenerApplication.class) + @MinimalIntegrationTestContextConfiguration + @TestPropertySource( + properties = { + "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.listener", + "springwolf.docket.payload-schema-format=openapi_v3", + "springwolf.docket.group-configs[0].group=FooMessage", + "springwolf.docket.group-configs[0].action-to-match=", + "springwolf.docket.group-configs[0].channel-name-to-match=", + "springwolf.docket.group-configs[0].message-name-to-match=.*Foo", + "springwolf.docket.group-configs[1].group=all & everything", + "springwolf.docket.group-configs[1].action-to-match=", + "springwolf.docket.group-configs[1].channel-name-to-match=.*", + "springwolf.docket.group-configs[1].message-name-to-match=", + }) + class GroupingTest { + @Autowired + private AsyncApiService asyncApiService; + + @Test + void shouldFindOnlyForGroupFoo() { + AsyncAPI asyncAPI = asyncApiService.getForGroupName("FooMessage").get(); + + assertThat(asyncAPI.getChannels().keySet()).containsExactlyInAnyOrder("listener-channel"); + assertThat(asyncAPI.getChannels().get("listener-channel").getMessages()) + .containsOnlyKeys( + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys("listener-channel_receive_listen3", "listener-channel_receive_listen4"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(asyncAPI.getComponents().getSchemas()) + .containsOnlyKeys( + "HeadersNotDocumented", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaReference.class); + SchemaReference fooSchemaRef = (SchemaReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooSchemaRef.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication.Foo"); + } + + @Test + void shouldFindAllForGroupAll() { + // given + AsyncAPI fullApi = asyncApiService.getAsyncAPI(); + + // when + AsyncAPI asyncAPIOpt = + asyncApiService.getForGroupName("all & everything").get(); + + // then + + // String and Integer get filtered. + // Question: Why are they in the fullApi in the first place, if not referenced? (inline schema) + fullApi.getComponents().getSchemas().remove(String.class.getName()); + fullApi.getComponents().getSchemas().remove(Integer.class.getName()); + + assertThat(asyncAPIOpt).isEqualTo(fullApi); + } + } + + private AsyncApiService createStandaloneAsyncApiService(ConfigurableEnvironment environment, String basePackage) { + DefaultStandaloneApplication standaloneApplication = DefaultStandaloneApplication.builder() + .addScanPackage(basePackage) + .setEnvironment(environment) + .buildAndStart(); + return standaloneApplication.getAsyncApiService(); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/polymorphic/PolymorphicPayloadApplication.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/polymorphic/PolymorphicPayloadApplication.java index 294ea91f2..83b246b7a 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/polymorphic/PolymorphicPayloadApplication.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/polymorphic/PolymorphicPayloadApplication.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.github.springwolf.core.asyncapi.annotations.AsyncListener; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.swagger.v3.oas.annotations.media.DiscriminatorMapping; import io.swagger.v3.oas.annotations.media.Schema; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -23,13 +24,20 @@ public void listen(Payload payload) {} public record Payload(Pet pet) {} - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type") @JsonSubTypes( value = { @JsonSubTypes.Type(value = Dog.class, name = "dog"), @JsonSubTypes.Type(value = Cat.class, name = "cat"), }) - @Schema(oneOf = {Dog.class, Cat.class}) + @Schema( + discriminatorProperty = "type", + discriminatorMapping = { + @DiscriminatorMapping(value = "dog", schema = Dog.class), + @DiscriminatorMapping(value = "cat", schema = Cat.class) + }, + oneOf = {Dog.class, Cat.class}, + subTypes = {Dog.class, Cat.class}) public interface Pet { String getType(); } diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/PayloadSchemaFormatIntegrationTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/PayloadSchemaFormatIntegrationTest.java new file mode 100644 index 000000000..09b35dbfb --- /dev/null +++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/PayloadSchemaFormatIntegrationTest.java @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.examples.kafka; + +import io.github.springwolf.asyncapi.v3.jackson.AsyncApiSerializerService; +import io.github.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializerService; +import io.github.springwolf.asyncapi.v3.model.AsyncAPI; +import io.github.springwolf.core.standalone.DefaultStandaloneApplication; +import io.github.springwolf.core.standalone.StandaloneApplication; +import io.github.springwolf.core.standalone.StandaloneEnvironmentLoader; +import org.junit.jupiter.api.Test; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PayloadSchemaFormatIntegrationTest { + @Test + void asyncApiStandaloneArtifactTest() throws Exception { + // given + ConfigurableEnvironment environment = StandaloneEnvironmentLoader.load(); + environment + .getPropertySources() + .addFirst(new MapPropertySource( + "env", Map.of("springwolf.docket.payload-schema-format", "openapi_v3_1"))); + StandaloneApplication standaloneApplication = DefaultStandaloneApplication.builder() + .setEnvironment(environment) + .buildAndStart(); + + // when + AsyncAPI asyncApi = standaloneApplication.getAsyncApiService().getAsyncAPI(); + + // then + assertThat(asyncApi).isNotNull(); + + AsyncApiSerializerService serializerService = new DefaultAsyncApiSerializerService(); + String actual = serializerService.toJsonString(asyncApi); + String actualPatched = actual.replace("localhost:9092", "kafka:29092"); + Files.writeString(Path.of("src", "test", "resources", "asyncapi.openapiv31.actual.json"), actualPatched); + + // then + InputStream s = this.getClass().getResourceAsStream("/asyncapi.openapiv31.json"); + String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim(); + assertThat(actualPatched).isEqualTo(expected); + } +} diff --git a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.openapiv31.json b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.openapiv31.json new file mode 100644 index 000000000..593445035 --- /dev/null +++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.openapiv31.json @@ -0,0 +1,1950 @@ +{ + "asyncapi": "3.0.0", + "info": { + "title": "Springwolf example project - Kafka", + "version": "1.0.0", + "description": "Springwolf [example project](https://github.com/springwolf/springwolf-core/tree/master/springwolf-examples/springwolf-kafka-example) to demonstrate springwolfs abilities, including **markdown** support for descriptions.", + "termsOfService": "http://asyncapi.org/terms", + "contact": { + "name": "springwolf", + "url": "https://github.com/springwolf/springwolf-core", + "email": "example@example.com" + }, + "license": { + "name": "Apache License 2.0" + }, + "x-generator": "springwolf" + }, + "defaultContentType": "application/json", + "servers": { + "kafka-server": { + "host": "kafka:29092", + "protocol": "kafka" + } + }, + "channels": { + "another-topic": { + "address": "another-topic", + "messages": { + "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "avro-topic": { + "address": "avro-topic", + "messages": { + "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "example-topic": { + "address": "example-topic", + "messages": { + "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "integer-topic": { + "address": "integer-topic", + "messages": { + "java.lang.Integer": { + "$ref": "#/components/messages/java.lang.Integer" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "multi-payload-topic": { + "address": "multi-payload-topic", + "messages": { + "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + }, + "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + }, + "javax.money.MonetaryAmount": { + "$ref": "#/components/messages/javax.money.MonetaryAmount" + } + }, + "bindings": { + "kafka": { + "topic": "multi-payload-topic", + "partitions": 3, + "replicas": 1, + "topicConfiguration": { + "cleanup.policy": [ + "compact", + "delete" + ], + "retention.ms": 86400000, + "retention.bytes": -1, + "delete.retention.ms": 86400000, + "max.message.bytes": 1048588 + }, + "bindingVersion": "0.5.0" + } + } + }, + "no-payload-used-topic": { + "address": "no-payload-used-topic", + "messages": { + "PayloadNotUsed": { + "$ref": "#/components/messages/PayloadNotUsed" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "nullable-topic": { + "address": "nullable-topic", + "messages": { + "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "protobuf-topic": { + "address": "protobuf-topic", + "messages": { + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "string-topic": { + "address": "string-topic", + "messages": { + "io.github.springwolf.examples.kafka.consumers.StringConsumer.StringEnvelope": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.consumers.StringConsumer.StringEnvelope" + }, + "java.lang.String": { + "$ref": "#/components/messages/java.lang.String" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "topic-defined-via-asyncPublisher-annotation": { + "address": "topic-defined-via-asyncPublisher-annotation", + "messages": { + "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" + } + }, + "servers": [ + { + "$ref": "#/servers/kafka-server" + } + ], + "bindings": { } + }, + "vehicle-topic": { + "address": "vehicle-topic", + "messages": { + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "xml-topic": { + "address": "xml-topic", + "messages": { + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "yaml-topic": { + "address": "yaml-topic", + "messages": { + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + } + }, + "components": { + "schemas": { + "HeadersNotDocumented": { + "title": "HeadersNotDocumented", + "type": "object", + "properties": { }, + "description": "There can be headers, but they are not explicitly documented.", + "examples": [ + { } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "description": "There can be headers, but they are not explicitly documented.", + "title": "HeadersNotDocumented", + "type": "object" + } + }, + "HeadersNotUsed": { + "title": "HeadersNotUsed", + "type": "object", + "properties": { }, + "description": "No headers are present.", + "examples": [ + { } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "description": "No headers are present.", + "title": "HeadersNotUsed", + "type": "object" + } + }, + "PayloadNotUsed": { + "title": "PayloadNotUsed", + "type": "object", + "properties": { }, + "description": "No payload specified", + "examples": [ + { } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "description": "No payload specified", + "title": "PayloadNotUsed", + "type": "object" + } + }, + "SpringDefaultHeaderAndCloudEvent": { + "title": "SpringDefaultHeaderAndCloudEvent", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" + ] + }, + "ce_id": { + "type": "string", + "description": "CloudEvent Id Header", + "enum": [ + "2c60089e-6f39-459d-8ced-2d6df7e4c03a" + ], + "examples": [ + "2c60089e-6f39-459d-8ced-2d6df7e4c03a" + ] + }, + "ce_source": { + "type": "string", + "description": "CloudEvent Source Header", + "enum": [ + "http://localhost" + ], + "examples": [ + "http://localhost" + ] + }, + "ce_specversion": { + "type": "string", + "description": "CloudEvent Spec Version Header", + "enum": [ + "1.0" + ], + "examples": [ + "1.0" + ] + }, + "ce_subject": { + "type": "string", + "description": "CloudEvent Subject Header", + "enum": [ + "Springwolf example project - Kafka" + ], + "examples": [ + "Springwolf example project - Kafka" + ] + }, + "ce_time": { + "type": "string", + "description": "CloudEvent Time Header", + "enum": [ + "2023-10-28 20:01:23+00:00" + ], + "examples": [ + "2023-10-28 20:01:23+00:00" + ] + }, + "ce_type": { + "type": "string", + "description": "CloudEvent Payload Type Header", + "enum": [ + "NestedPayloadDto.v1" + ], + "examples": [ + "NestedPayloadDto.v1" + ] + }, + "content-type": { + "type": "string", + "description": "CloudEvent Content-Type Header", + "enum": [ + "application/json" + ], + "examples": [ + "application/json" + ] + } + }, + "description": "Spring __TypeId__ and CloudEvent Headers", + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto", + "ce_id": "2c60089e-6f39-459d-8ced-2d6df7e4c03a", + "ce_source": "http://localhost", + "ce_specversion": "1.0", + "ce_subject": "Springwolf example project - Kafka", + "ce_time": "2023-10-28 20:01:23+00:00", + "ce_type": "NestedPayloadDto.v1", + "content-type": "application/json" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "description": "Spring __TypeId__ and CloudEvent Headers", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" + ], + "type": "string" + }, + "ce_id": { + "description": "CloudEvent Id Header", + "enum": [ + "2c60089e-6f39-459d-8ced-2d6df7e4c03a" + ], + "type": "string" + }, + "ce_source": { + "description": "CloudEvent Source Header", + "enum": [ + "http://localhost" + ], + "type": "string" + }, + "ce_specversion": { + "description": "CloudEvent Spec Version Header", + "enum": [ + "1.0" + ], + "type": "string" + }, + "ce_subject": { + "description": "CloudEvent Subject Header", + "enum": [ + "Springwolf example project - Kafka" + ], + "type": "string" + }, + "ce_time": { + "description": "CloudEvent Time Header", + "enum": [ + "2023-10-28 20:01:23+00:00" + ], + "type": "string" + }, + "ce_type": { + "description": "CloudEvent Payload Type Header", + "enum": [ + "NestedPayloadDto.v1" + ], + "type": "string" + }, + "content-type": { + "description": "CloudEvent Content-Type Header", + "enum": [ + "application/json" + ], + "type": "string" + } + }, + "title": "SpringDefaultHeaderAndCloudEvent", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-AnotherPayloadAvroDto": { + "title": "SpringKafkaDefaultHeaders-AnotherPayloadAvroDto", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-AnotherPayloadAvroDto", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-AnotherPayloadDto": { + "title": "SpringKafkaDefaultHeaders-AnotherPayloadDto", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-AnotherPayloadDto", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-AnotherTopic": { + "title": "SpringKafkaDefaultHeaders-AnotherTopic", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Type ID" + }, + "my_uuid_field": { + "type": "string", + "description": "Event identifier", + "format": "uuid" + } + }, + "examples": [ + { + "__TypeId__": "string", + "my_uuid_field": "3fa85f64-5717-4562-b3fc-2c963f66afa6" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Type ID", + "type": "string" + }, + "my_uuid_field": { + "description": "Event identifier", + "format": "uuid", + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-AnotherTopic", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-ExamplePayloadDto-546532105": { + "title": "SpringKafkaDefaultHeaders-ExamplePayloadDto-546532105", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + ] + }, + "kafka_offset": { + "type": "integer", + "format": "int32", + "examples": [ + 0 + ] + }, + "kafka_receivedMessageKey": { + "type": "string", + "examples": [ + "\"string\"" + ] + }, + "kafka_recordMetadata": { + "type": "object", + "examples": [ + { } + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto", + "kafka_offset": 0, + "kafka_receivedMessageKey": "string", + "kafka_recordMetadata": { } + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + ], + "type": "string" + }, + "kafka_offset": { + "format": "int32", + "type": "integer" + }, + "kafka_receivedMessageKey": { + "type": "string" + }, + "kafka_recordMetadata": { + "type": "object" + } + }, + "title": "SpringKafkaDefaultHeaders-ExamplePayloadDto-546532105", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-Message": { + "title": "SpringKafkaDefaultHeaders-Message", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-Message", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-MonetaryAmount": { + "title": "SpringKafkaDefaultHeaders-MonetaryAmount", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "javax.money.MonetaryAmount" + ], + "examples": [ + "javax.money.MonetaryAmount" + ] + } + }, + "examples": [ + { + "__TypeId__": "javax.money.MonetaryAmount" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "javax.money.MonetaryAmount" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-MonetaryAmount", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-PayloadNotUsed": { + "title": "SpringKafkaDefaultHeaders-PayloadNotUsed", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "PayloadNotUsed" + ], + "examples": [ + "PayloadNotUsed" + ] + } + }, + "examples": [ + { + "__TypeId__": "PayloadNotUsed" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "PayloadNotUsed" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-PayloadNotUsed", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-RequiredAndNullablePayloadDto": { + "title": "SpringKafkaDefaultHeaders-RequiredAndNullablePayloadDto", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-RequiredAndNullablePayloadDto", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-VehicleBase": { + "title": "SpringKafkaDefaultHeaders-VehicleBase", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-VehicleBase", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-XmlPayloadDto": { + "title": "SpringKafkaDefaultHeaders-XmlPayloadDto", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-XmlPayloadDto", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-YamlPayloadDto": { + "title": "SpringKafkaDefaultHeaders-YamlPayloadDto", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-YamlPayloadDto", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-integer": { + "title": "SpringKafkaDefaultHeaders-integer", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "java.lang.Integer" + ], + "examples": [ + "java.lang.Integer" + ] + } + }, + "examples": [ + { + "__TypeId__": "java.lang.Integer" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "java.lang.Integer" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-integer", + "type": "object" + } + }, + "SpringKafkaDefaultHeaders-string": { + "title": "SpringKafkaDefaultHeaders-string", + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "java.lang.String" + ], + "examples": [ + "java.lang.String" + ] + } + }, + "examples": [ + { + "__TypeId__": "java.lang.String" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "java.lang.String" + ], + "type": "string" + } + }, + "title": "SpringKafkaDefaultHeaders-string", + "type": "object" + } + }, + "io.github.springwolf.examples.kafka.consumers.StringConsumer.StringEnvelope": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "type": "string", + "description": "Payload description using @Schema annotation and @AsyncApiPayload within envelope class", + "example": "\"string\"", + "maxLength": 100 + } + }, + "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "example": { + "examplePayloadAvroDto": { + "someLong": 0, + "someString": "string" + }, + "someEnum": "FOO1" + }, + "properties": { + "examplePayloadAvroDto": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dto.avro.ExamplePayloadAvroDto" + }, + "someEnum": { + "type": "string", + "enum": [ + "FOO1", + "FOO2", + "FOO3" + ] + } + }, + "title": "AnotherPayloadAvroDto" + } + }, + "io.github.springwolf.examples.kafka.dto.avro.ExamplePayloadAvroDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "example": { + "someLong": 0, + "someString": "string" + }, + "properties": { + "someLong": { + "type": "integer", + "format": "int64" + }, + "someString": { + "type": "string" + } + }, + "title": "ExamplePayloadAvroDto" + } + }, + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "example": { + "someEnum": "FOO1", + "someLong": 0, + "someString": "string" + }, + "properties": { + "someEnum": { + "type": "string", + "enum": [ + "FOO1", + "FOO2", + "FOO3", + "UNRECOGNIZED" + ] + }, + "someLong": { + "type": "integer", + "format": "int64" + }, + "someString": { + "type": "string" + } + }, + "title": "Message" + } + }, + "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "description": "Another payload model", + "example": { + "example": { + "someEnum": "FOO2", + "someLong": 5, + "someString": "some string value" + }, + "foo": "bar" + }, + "properties": { + "example": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + }, + "foo": { + "type": "string", + "description": "Foo field", + "example": "bar", + "maxLength": 100 + } + }, + "required": [ + "example" + ], + "title": "AnotherPayloadDto" + } + }, + "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "description": "Example payload model demonstrating markdown text styling:\n**bold**, *cursive* and underlined\n", + "example": { + "someEnum": "FOO2", + "someLong": 5, + "someString": "some string value" + }, + "properties": { + "someEnum": { + "type": "string", + "description": "Some enum field", + "enum": [ + "FOO1", + "FOO2", + "FOO3" + ], + "example": "FOO2" + }, + "someLong": { + "type": "integer", + "format": "int64", + "description": "Some long field", + "example": 5, + "minimum": 0 + }, + "someString": { + "type": "string", + "description": "### Some string field with Markdown\n\n- **bold**\n- *cursive*\n- images: \"Springwolf\"\n- and code blocks (json, http, java)\n ```json\n {\n \"key1\":\"value1\",\n \"key2\":\"value2\"\n }\n ```\n", + "example": "some string value" + } + }, + "required": [ + "someEnum", + "someString" + ], + "title": "ExamplePayloadDto" + } + }, + "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "description": "Payload model with nested complex types", + "example": { + "examplePayloads": [ + { + "someEnum": "FOO2", + "someLong": 5, + "someString": "some string value" + } + ], + "someStrings": [ + "some string value" + ] + }, + "properties": { + "examplePayloads": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + } + }, + "someStrings": { + "type": "array", + "items": { + "type": "string", + "description": "Some string field", + "example": "some string value" + }, + "uniqueItems": true + } + }, + "title": "NestedPayloadDto" + } + }, + "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "description": "Demonstrate required and nullable. Note, @Schema is only descriptive without nullability check", + "example": { + "enumField": "COMPLEX1", + "notRequiredField": "string", + "requiredAndNullableField": "string", + "requiredButNullableField": "string", + "requiredField": "string" + }, + "properties": { + "enumField": { + "type": "string", + "description": "Follows OpenAPI 3.1 spec", + "enum": [ + "COMPLEX1", + "COMPLEX2" + ] + }, + "notRequiredField": { + "type": "string", + "description": "This field can be skipped, but value cannot be null" + }, + "requiredAndNullableField": { + "type": "string", + "description": "This field can be skipped, or value can be null or present" + }, + "requiredButNullableField": { + "type": "string", + "description": "This field must be present, but value can be null" + }, + "requiredField": { + "type": "string", + "description": "This field must be present, and value cannot be null" + } + }, + "required": [ + "enumField", + "requiredButNullableField", + "requiredField" + ], + "title": "RequiredAndNullablePayloadDto" + } + }, + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "type": "string", + "example": "FOO10string", + "properties": { + "someAttribute": { + "type": "string", + "xml": { + "attribute": true + } + }, + "someEnum": { + "type": "string", + "enum": [ + "FOO1", + "FOO2", + "FOO3" + ] + }, + "someLong": { + "type": "integer", + "format": "int64" + }, + "someString": { + "type": "string" + } + }, + "title": "XmlPayloadDto" + } + }, + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "type": "string", + "example": "someEnum: FOO1\nsomeLong: 0\nsomeString: string\n", + "properties": { + "someEnum": { + "type": "string", + "enum": [ + "FOO1", + "FOO2", + "FOO3" + ] + }, + "someLong": { + "type": "integer", + "format": "int64" + }, + "someString": { + "type": "string" + } + }, + "title": "YamlPayloadDto" + } + }, + "io.github.springwolf.examples.kafka.dtos.discriminator.EnginePower": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "example": { + "hp": 0, + "torque": 0 + }, + "properties": { + "hp": { + "type": "integer", + "format": "int32" + }, + "torque": { + "type": "integer", + "format": "int32" + } + }, + "title": "EnginePower" + } + }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "description": "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)", + "discriminator": { + "propertyName": "vehicleType", + "mapping": { + "VehicleElectricPayloadDto": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleElectricPayloadDto", + "VehicleGasolinePayloadDto": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleGasolinePayloadDto" + } + }, + "example": { + "batteryCapacity": 0, + "chargeTime": 0, + "enginePower": { + "hp": 0, + "torque": 0 + }, + "powerSource": "string", + "topSpeed": 0, + "vehicleType": "string" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleElectricPayloadDto" + }, + { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleGasolinePayloadDto" + } + ], + "properties": { + "enginePower": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.EnginePower" + }, + "powerSource": { + "type": "string" + }, + "topSpeed": { + "type": "integer", + "format": "int32" + }, + "vehicleType": { + "type": "string" + } + }, + "title": "VehicleBase" + } + }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleElectricPayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + }, + { + "type": "object", + "properties": { + "batteryCapacity": { + "type": "integer", + "format": "int32" + }, + "chargeTime": { + "type": "integer", + "format": "int32" + } + } + } + ], + "description": "Electric vehicle implementation of VehicleBase", + "example": { + "batteryCapacity": 0, + "chargeTime": 0, + "enginePower": { + "hp": 0, + "torque": 0 + }, + "powerSource": "string", + "topSpeed": 0, + "vehicleType": "string" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleGasolinePayloadDto": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + }, + { + "type": "object", + "properties": { + "fuelCapacity": { + "type": "integer", + "format": "int32" + } + } + } + ], + "description": "Gasoline vehicle implementation of VehicleBase", + "example": { + "enginePower": { + "hp": 0, + "torque": 0 + }, + "fuelCapacity": 0, + "powerSource": "string", + "topSpeed": 0, + "vehicleType": "string" + } + } + }, + "java.lang.Integer": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "type": "integer", + "format": "int32", + "example": 0 + } + }, + "java.lang.String": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "type": "string", + "example": "\"string\"" + } + }, + "javax.money.MonetaryAmount": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "example": { + "amount": 99.99, + "currency": "USD" + }, + "properties": { + "amount": { + "type": "number", + "example": 99.99, + "minimum": 0.01 + }, + "currency": { + "type": "string", + "example": "USD" + } + } + } + } + }, + "messages": { + "PayloadNotUsed": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-PayloadNotUsed" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "title": "PayloadNotUsed", + "type": "object", + "properties": { }, + "description": "No payload specified" + } + }, + "name": "PayloadNotUsed", + "title": "PayloadNotUsed", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.consumers.StringConsumer.StringEnvelope": { + "headers": { + "$ref": "#/components/schemas/HeadersNotUsed" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.consumers.StringConsumer.StringEnvelope" + } + }, + "name": "StringPayload", + "title": "StringEnvelope", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto": { + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" + } + }, + "name": "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto", + "title": "AnotherPayloadAvroDto", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-Message" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message" + } + }, + "name": "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message", + "title": "Message", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-AnotherTopic" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + } + }, + "name": "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto", + "title": "AnotherPayloadDto", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-ExamplePayloadDto-546532105" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + } + }, + "name": "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto", + "title": "ExamplePayloadDto", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto": { + "headers": { + "$ref": "#/components/schemas/SpringDefaultHeaderAndCloudEvent" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" + } + }, + "name": "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto", + "title": "NestedPayloadDto", + "bindings": { + "kafka": { + "key": { + "type": "string", + "description": "Kafka Producer Message Key", + "examples": [ + "example-key" + ] + }, + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-RequiredAndNullablePayloadDto" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto" + } + }, + "name": "io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto", + "title": "RequiredAndNullablePayloadDto", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto": { + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + } + }, + "contentType": "text/xml", + "name": "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto", + "title": "XmlPayloadDto", + "description": "Showcases a xml based message", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto": { + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + } + }, + "contentType": "application/yaml", + "name": "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto", + "title": "YamlPayloadDto", + "description": "Showcases a yaml based message", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-VehicleBase" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + }, + "name": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase", + "title": "VehicleBase", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "java.lang.Integer": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-integer" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "type": "integer", + "format": "int32", + "example": 0 + } + } + }, + "name": "java.lang.Integer", + "title": "integer", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "java.lang.String": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-string" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "schemaFormat": "application/vnd.oai.openapi;version=3.1.0", + "schema": { + "type": "string", + "example": "\"string\"" + } + } + }, + "name": "java.lang.String", + "title": "string", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, + "javax.money.MonetaryAmount": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-MonetaryAmount" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/javax.money.MonetaryAmount" + } + }, + "name": "javax.money.MonetaryAmount", + "title": "MonetaryAmount", + "bindings": { + "kafka": { + "key": { + "type": "string", + "description": "Kafka Consumer Message Key", + "examples": [ + "example-key" + ] + }, + "bindingVersion": "0.5.0" + } + } + } + } + }, + "operations": { + "another-topic_receive_receiveAnotherPayloadBatched": { + "action": "receive", + "channel": { + "$ref": "#/channels/another-topic" + }, + "bindings": { + "kafka": { + "groupId": { + "type": "string", + "enum": [ + "example-group-id" + ] + }, + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/another-topic/messages/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + } + ] + }, + "another-topic_send_sendMessage": { + "action": "send", + "channel": { + "$ref": "#/channels/another-topic" + }, + "title": "another-topic_send", + "description": "Auto-generated description", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/another-topic/messages/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + } + ] + }, + "avro-topic_receive_receiveExampleAvroPayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/avro-topic" + }, + "title": "avro-topic_receive", + "description": "Requires a running kafka-schema-registry. See docker-compose.yml to start it", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/avro-topic/messages/io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" + } + ] + }, + "example-topic_receive_receiveExamplePayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/example-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/example-topic/messages/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + } + ] + }, + "integer-topic_receive_receiveIntegerPayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/integer-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/integer-topic/messages/java.lang.Integer" + } + ] + }, + "multi-payload-topic_receive_ExampleClassLevelKafkaListener": { + "action": "receive", + "channel": { + "$ref": "#/channels/multi-payload-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/multi-payload-topic/messages/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" + }, + { + "$ref": "#/channels/multi-payload-topic/messages/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" + }, + { + "$ref": "#/channels/multi-payload-topic/messages/javax.money.MonetaryAmount" + } + ] + }, + "multi-payload-topic_receive_receiveMonetaryAmount": { + "action": "receive", + "channel": { + "$ref": "#/channels/multi-payload-topic" + }, + "title": "multi-payload-topic_receive", + "description": "Override description in the AsyncListener annotation with servers at kafka:29092", + "bindings": { + "kafka": { + "groupId": { + "type": "string", + "enum": [ + "foo-groupId" + ] + }, + "clientId": { + "type": "string", + "enum": [ + "foo-clientId" + ] + }, + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/multi-payload-topic/messages/javax.money.MonetaryAmount" + } + ] + }, + "no-payload-used-topic_receive_receiveExamplePayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/no-payload-used-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/no-payload-used-topic/messages/PayloadNotUsed" + } + ] + }, + "nullable-topic_receive_receiveNullablePayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/nullable-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/nullable-topic/messages/io.github.springwolf.examples.kafka.dtos.RequiredAndNullablePayloadDto" + } + ] + }, + "protobuf-topic_receive_receiveExampleProtobufPayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/protobuf-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/protobuf-topic/messages/io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto.Message" + } + ] + }, + "string-topic_receive_receiveStringPayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/string-topic" + }, + "title": "string-topic_receive", + "description": "Final classes (like String) can be documented using an envelope class and the @AsyncApiPayload annotation.", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/string-topic/messages/io.github.springwolf.examples.kafka.consumers.StringConsumer.StringEnvelope" + }, + { + "$ref": "#/channels/string-topic/messages/java.lang.String" + } + ] + }, + "topic-defined-via-asyncPublisher-annotation_send_sendMessage": { + "action": "send", + "channel": { + "$ref": "#/channels/topic-defined-via-asyncPublisher-annotation" + }, + "title": "topic-defined-via-asyncPublisher-annotation_send", + "description": "Custom, optional description defined in the AsyncPublisher annotation", + "bindings": { + "kafka": { + "clientId": { + "type": "string", + "enum": [ + "foo-clientId" + ] + }, + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/topic-defined-via-asyncPublisher-annotation/messages/io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" + } + ] + }, + "vehicle-topic_receive_receiveExamplePayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/vehicle-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/vehicle-topic/messages/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + ] + }, + "xml-topic_receive_receiveExamplePayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/xml-topic" + }, + "title": "xml-topic_receive", + "description": "Auto-generated description", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/xml-topic/messages/io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + } + ] + }, + "yaml-topic_receive_receiveExamplePayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/yaml-topic" + }, + "title": "yaml-topic_receive", + "description": "Auto-generated description", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/yaml-topic/messages/io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + } + ] + } + } +} \ No newline at end of file diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java index 0d4698d09..59d7a0842 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java @@ -30,6 +30,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeExtractor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.configuration.docket.DefaultAsyncApiDocketService; @@ -82,7 +83,8 @@ CloudStreamFunctionChannelsScanner.class, CloudStreamFunctionOperationsScanner.class, FunctionalChannelBeanBuilder.class, - SpringwolfConfigProperties.class + SpringwolfConfigProperties.class, + ModelConvertersProvider.class }) @TestPropertySource( properties = { diff --git a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/controller/SpringwolfJmsControllerIntegrationTest.java b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/controller/SpringwolfJmsControllerIntegrationTest.java index a5ba0e3a3..b6f8b42f4 100644 --- a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/controller/SpringwolfJmsControllerIntegrationTest.java +++ b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/controller/SpringwolfJmsControllerIntegrationTest.java @@ -11,6 +11,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeExtractor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; @@ -63,6 +64,7 @@ SchemaWalkerProvider.class, ExampleJsonValueGenerator.class, SpringwolfConfigProperties.class, + ModelConvertersProvider.class }) @TestPropertySource( properties = { diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/controller/SpringwolfKafkaControllerIntegrationTest.java b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/controller/SpringwolfKafkaControllerIntegrationTest.java index 991777d39..37f036425 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/controller/SpringwolfKafkaControllerIntegrationTest.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/controller/SpringwolfKafkaControllerIntegrationTest.java @@ -11,6 +11,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeExtractor; +import io.github.springwolf.core.asyncapi.schemas.ModelConvertersProvider; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; @@ -63,6 +64,7 @@ SchemaWalkerProvider.class, ExampleJsonValueGenerator.class, SpringwolfConfigProperties.class, + ModelConvertersProvider.class }) @TestPropertySource( properties = {