From d63069173351e5a1c04ce19d1376650e3efa4a19 Mon Sep 17 00:00:00 2001 From: Bartosz Michalik Date: Wed, 28 Dec 2022 15:35:14 +0100 Subject: [PATCH] preserve descriptions next to the $ref some code cleanup --- pom.xml | 2 +- .../blender/impl/SwaggerConverterClone.java | 56 +--- .../postprocess/ComposedPostprocessor.java | 4 +- .../ConvertOneOfToAllOffInheritance.java | 4 +- .../postprocess/RenameTypesPostprocessor.java | 24 +- .../impl/specifications/NameConverter.java | 2 +- .../blender/impl/util/IdSchemaResolver.java | 9 +- .../blender/impl/util/SerializationUtils.java | 3 +- .../blender/impl/yaml/SchemaSerializer.java | 5 +- .../blender/impl/yaml/YamlMapperFactory.java | 4 +- .../blender/parser/OpenAPIResolver.java | 6 +- .../sonata/blender/parser/ResolverCache.java | 24 +- .../blender/impl/ProductSpecReaderTest.java | 3 +- .../impl/ValidateSpecificationTest.java | 12 +- .../UrnBasedNamingStrategyTest.java | 2 +- src/test/resources/oas/test-spec.yaml | 278 +----------------- src/test/resources/oas/toInject.json | 24 ++ 17 files changed, 96 insertions(+), 366 deletions(-) create mode 100644 src/test/resources/oas/toInject.json diff --git a/pom.xml b/pom.xml index f22a1d3..9b300db 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ com.amartus.sonata blender SonataBlendingTool - 1.9.5-SNAPSHOT + 1.9.5 6.2.0 2.14.0 diff --git a/src/main/java/com/amartus/sonata/blender/impl/SwaggerConverterClone.java b/src/main/java/com/amartus/sonata/blender/impl/SwaggerConverterClone.java index d5af090..8e811b9 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/SwaggerConverterClone.java +++ b/src/main/java/com/amartus/sonata/blender/impl/SwaggerConverterClone.java @@ -18,19 +18,7 @@ package com.amartus.sonata.blender.impl; -import io.swagger.models.ArrayModel; -import io.swagger.models.ComposedModel; -import io.swagger.models.ExternalDocs; -import io.swagger.models.Model; -import io.swagger.models.ModelImpl; -import io.swagger.models.Path; -import io.swagger.models.RefModel; -import io.swagger.models.RefPath; -import io.swagger.models.RefResponse; -import io.swagger.models.Response; -import io.swagger.models.Scheme; -import io.swagger.models.SecurityRequirement; -import io.swagger.models.Swagger; +import io.swagger.models.*; import io.swagger.models.auth.ApiKeyAuthDefinition; import io.swagger.models.auth.OAuth2Definition; import io.swagger.models.auth.SecuritySchemeDefinition; @@ -38,38 +26,20 @@ import io.swagger.models.parameters.BodyParameter; import io.swagger.models.parameters.RefParameter; import io.swagger.models.parameters.SerializableParameter; -import io.swagger.models.properties.AbstractNumericProperty; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.ComposedProperty; -import io.swagger.models.properties.FileProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; -import io.swagger.models.properties.StringProperty; +import io.swagger.models.properties.*; import io.swagger.parser.SwaggerParser; import io.swagger.parser.SwaggerResolver; import io.swagger.parser.util.SwaggerDeserializationResult; import io.swagger.v3.core.util.Json; import io.swagger.v3.core.util.PrimitiveType; import io.swagger.v3.core.util.Yaml; -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.ExternalDocumentation; -import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.*; import io.swagger.v3.oas.models.headers.Header; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.media.ArraySchema; -import io.swagger.v3.oas.models.media.ComposedSchema; -import io.swagger.v3.oas.models.media.Content; -import io.swagger.v3.oas.models.media.Discriminator; -import io.swagger.v3.oas.models.media.FileSchema; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.*; import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.responses.ApiResponse; @@ -90,12 +60,7 @@ import org.apache.commons.lang3.StringUtils; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; /** @@ -103,10 +68,10 @@ * with override of some private access modifiers to protected */ class SwaggerConverterClone implements SwaggerParserExtension { - private List globalConsumes = new ArrayList<>(); - private List globalProduces = new ArrayList<>(); - private Components components = new Components(); - private Map globalV2Parameters = new HashMap<>(); + private final List globalConsumes = new ArrayList<>(); + private final List globalProduces = new ArrayList<>(); + private final Components components = new Components(); + private final Map globalV2Parameters = new HashMap<>(); @Override public SwaggerParseResult readLocation(String url, List auths, ParseOptions options) { @@ -122,8 +87,7 @@ public SwaggerParseResult readLocation(String url, List auth @Override public SwaggerParseResult readContents(String swaggerAsString, List auth, ParseOptions options) { - SwaggerDeserializationResult result = new SwaggerParser().readWithInfo(swaggerAsString, options == null ? - true : options.isResolve()); + SwaggerDeserializationResult result = new SwaggerParser().readWithInfo(swaggerAsString, options == null || options.isResolve()); if (options != null) { if (options.isResolve()) { diff --git a/src/main/java/com/amartus/sonata/blender/impl/postprocess/ComposedPostprocessor.java b/src/main/java/com/amartus/sonata/blender/impl/postprocess/ComposedPostprocessor.java index 4f92632..292f554 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/postprocess/ComposedPostprocessor.java +++ b/src/main/java/com/amartus/sonata/blender/impl/postprocess/ComposedPostprocessor.java @@ -31,12 +31,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.amartus.sonata.blender.impl.postprocess.RenameTypesPostprocessor.*; +import static com.amartus.sonata.blender.impl.postprocess.RenameTypesPostprocessor.NameConverter; public class ComposedPostprocessor implements Consumer { private static final Logger log = LoggerFactory.getLogger(ComposedPostprocessor.class); - private List> postprocessors = List.of( + private final List> postprocessors = List.of( new RemoveSuperflousTypeDeclarations(), new RenameTypesPostprocessor(converter()), new PropertyEnumExternalize(), diff --git a/src/main/java/com/amartus/sonata/blender/impl/postprocess/ConvertOneOfToAllOffInheritance.java b/src/main/java/com/amartus/sonata/blender/impl/postprocess/ConvertOneOfToAllOffInheritance.java index 98a0c0e..86132f8 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/postprocess/ConvertOneOfToAllOffInheritance.java +++ b/src/main/java/com/amartus/sonata/blender/impl/postprocess/ConvertOneOfToAllOffInheritance.java @@ -46,8 +46,8 @@ public class ConvertOneOfToAllOffInheritance implements Consumer { private static final Logger log = LoggerFactory.getLogger(ConvertOneOfToAllOffInheritance.class); private OasWrapper openAPI; - private Predicate isReference = s -> s.get$ref() != null; - private Predicate isOneOf = s -> { + private final Predicate isReference = s -> s.get$ref() != null; + private final Predicate isOneOf = s -> { if (s instanceof ComposedSchema) { ComposedSchema c = (ComposedSchema) s; return c.getOneOf() != null && !c.getOneOf().isEmpty(); diff --git a/src/main/java/com/amartus/sonata/blender/impl/postprocess/RenameTypesPostprocessor.java b/src/main/java/com/amartus/sonata/blender/impl/postprocess/RenameTypesPostprocessor.java index 7be878b..2574191 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/postprocess/RenameTypesPostprocessor.java +++ b/src/main/java/com/amartus/sonata/blender/impl/postprocess/RenameTypesPostprocessor.java @@ -47,18 +47,26 @@ public void accept(OpenAPI openAPI) { substitutions.forEach((a,b) -> log.debug("Renaming {} to {}", a, b)); } - var newNames = new HashSet(substitutions.values()); + var newNames = new HashSet<>(substitutions.values()); if(newNames.size() < substitutions.size()) { log.warn("Conflicting substitution names. Skipping."); return; } - if(schemas.keySet().stream().anyMatch(newNames::contains)) { + if (schemas.keySet().stream().anyMatch(newNames::contains)) { log.warn("Name substitution already defined in the model. Skipping."); return; } schemas.values().forEach(s -> Optional.ofNullable(s.getExtensions()).ifPresent(e -> e.remove(extensionName))); renameSchemas(openAPI); renameReferences(openAPI); + cleanupExtensions(openAPI); + } + + private void cleanupExtensions(OpenAPI openAPI) { + var schemas = new OasWrapper(openAPI).schemas().values(); + schemas.forEach(s -> { + Optional.ofNullable(s.getExtensions()).ifPresent(e -> e.remove(extensionName)); + }); } private void renameSchemas(OpenAPI oas) { @@ -89,7 +97,6 @@ protected String convert(String ref) { private void renameReferences(OpenAPI openAPI) { new RenameReferences().accept(openAPI); new RenamePathReferences().accept(openAPI); - //FIXME rename refrences in response ref and body ref } protected Optional toName(Schema schema) { @@ -115,16 +122,11 @@ public void accept(OpenAPI openAPI) { }); schemas.forEach(RenameTypesPostprocessor.this::tryConverting); - - openAPI.getPaths().entrySet().stream().map(Map.Entry::getValue) - .flatMap(pi -> pi.readOperations().stream()); - } private Stream toOperations(OpenAPI oas) { - return Optional.ofNullable(oas.getPaths()) - .map(p -> p.entrySet().stream() - .map(Map.Entry::getValue).flatMap(pi -> pi.readOperations().stream()) + return Optional.ofNullable(oas.getPaths()) + .map(p -> p.values().stream().flatMap(pi -> pi.readOperations().stream()) ).orElse(Stream.empty()); } @@ -140,7 +142,7 @@ private Stream schemas(ApiResponse r) { } private Stream schemas(Content c) { - if(c == null) Stream.empty(); + if (c == null) return Stream.empty(); return c.values().stream().map(MediaType::getSchema); } diff --git a/src/main/java/com/amartus/sonata/blender/impl/specifications/NameConverter.java b/src/main/java/com/amartus/sonata/blender/impl/specifications/NameConverter.java index 2478142..8ef9bff 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/specifications/NameConverter.java +++ b/src/main/java/com/amartus/sonata/blender/impl/specifications/NameConverter.java @@ -18,7 +18,7 @@ public interface NameConverter extends Function { var uri = URI.create(id); diff --git a/src/main/java/com/amartus/sonata/blender/impl/util/IdSchemaResolver.java b/src/main/java/com/amartus/sonata/blender/impl/util/IdSchemaResolver.java index bf7a15e..4eed03d 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/util/IdSchemaResolver.java +++ b/src/main/java/com/amartus/sonata/blender/impl/util/IdSchemaResolver.java @@ -36,7 +36,7 @@ public class IdSchemaResolver { private static final Logger log = LoggerFactory.getLogger(IdSchemaResolver.class); - private UrnPredicate urnPredicate; + private final UrnPredicate urnPredicate; public IdSchemaResolver(String functionName) { this.urnPredicate = new UrnPredicate(functionName); @@ -72,7 +72,12 @@ private UrnPredicate(String functionName) { @Override public boolean test(Path path) { - var toInclude = namingStrategy.provideNameAndDiscriminator(null, read(path)) + var content = read(path); + if (content == null) { + log.debug("Not in json or yaml format: {}", path.toAbsolutePath().normalize()); + return false; + } + var toInclude = namingStrategy.provideNameAndDiscriminator(null, content) .map(n -> { String disc = n.getDiscriminatorValue(); return (disc.endsWith("all") || disc.endsWith(functionName)); diff --git a/src/main/java/com/amartus/sonata/blender/impl/util/SerializationUtils.java b/src/main/java/com/amartus/sonata/blender/impl/util/SerializationUtils.java index 90151a3..c071f08 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/util/SerializationUtils.java +++ b/src/main/java/com/amartus/sonata/blender/impl/util/SerializationUtils.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; +import io.swagger.v3.core.util.Json31; import io.swagger.v3.oas.models.OpenAPI; import org.openapitools.codegen.serializer.OpenAPISerializer; @@ -34,7 +35,7 @@ public static ObjectMapper yamlMapper() { } public static ObjectMapper jsonMapper() { - return enhance(new ObjectMapper()); + return enhance(Json31.mapper()); } private static ObjectMapper enhance(ObjectMapper mapper) { diff --git a/src/main/java/com/amartus/sonata/blender/impl/yaml/SchemaSerializer.java b/src/main/java/com/amartus/sonata/blender/impl/yaml/SchemaSerializer.java index db7881a..c5aa819 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/yaml/SchemaSerializer.java +++ b/src/main/java/com/amartus/sonata/blender/impl/yaml/SchemaSerializer.java @@ -19,7 +19,6 @@ package com.amartus.sonata.blender.impl.yaml; import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; @@ -31,7 +30,7 @@ public class SchemaSerializer extends JsonSerializer implements ResolvableSerializer { - private JsonSerializer defaultSerializer; + private final JsonSerializer defaultSerializer; public SchemaSerializer(JsonSerializer serializer) { defaultSerializer = serializer; @@ -47,7 +46,7 @@ public void resolve(SerializerProvider serializerProvider) throws JsonMappingExc @Override public void serialize( Schema value, JsonGenerator jgen, SerializerProvider provider) - throws IOException, JsonProcessingException { + throws IOException { // handle ref schema serialization skipping all other props if (StringUtils.isBlank(value.get$ref())) { diff --git a/src/main/java/com/amartus/sonata/blender/impl/yaml/YamlMapperFactory.java b/src/main/java/com/amartus/sonata/blender/impl/yaml/YamlMapperFactory.java index 6ec5b6f..4c20cdc 100644 --- a/src/main/java/com/amartus/sonata/blender/impl/yaml/YamlMapperFactory.java +++ b/src/main/java/com/amartus/sonata/blender/impl/yaml/YamlMapperFactory.java @@ -20,11 +20,11 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; -import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.core.util.Yaml31; public class YamlMapperFactory { public ObjectMapper createYaml() { - var mapper = Yaml.mapper(); + var mapper = Yaml31.mapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); return mapper; } diff --git a/src/main/java/com/amartus/sonata/blender/parser/OpenAPIResolver.java b/src/main/java/com/amartus/sonata/blender/parser/OpenAPIResolver.java index 4d5a7e9..1bf6573 100644 --- a/src/main/java/com/amartus/sonata/blender/parser/OpenAPIResolver.java +++ b/src/main/java/com/amartus/sonata/blender/parser/OpenAPIResolver.java @@ -21,8 +21,8 @@ public class OpenAPIResolver { private final ComponentsProcessor componentsProcessor; private final PathsProcessor pathProcessor; private final OperationProcessor operationsProcessor; - private io.swagger.v3.parser.OpenAPIResolver.Settings settings; - private Set resolveValidationMessages = new HashSet<>(); + private final io.swagger.v3.parser.OpenAPIResolver.Settings settings; + private final Set resolveValidationMessages = new HashSet<>(); public ResolverCache getCache() { return cache; @@ -32,7 +32,7 @@ public OpenAPIResolver(OpenAPI openApi, ResolverCache cache, io.swagger.v3.parse this.openApi = openApi; this.settings = settings != null ? settings : new io.swagger.v3.parser.OpenAPIResolver.Settings(); this.cache = cache; - componentsProcessor = new ComponentsProcessor(openApi,this.cache); + componentsProcessor = new ComponentsProcessor(openApi, this.cache); pathProcessor = new PathsProcessor(this.cache, openApi,this.settings); operationsProcessor = new OperationProcessor(cache, openApi); } diff --git a/src/main/java/com/amartus/sonata/blender/parser/ResolverCache.java b/src/main/java/com/amartus/sonata/blender/parser/ResolverCache.java index 7d3cc01..46813ac 100644 --- a/src/main/java/com/amartus/sonata/blender/parser/ResolverCache.java +++ b/src/main/java/com/amartus/sonata/blender/parser/ResolverCache.java @@ -26,8 +26,8 @@ import org.apache.commons.lang3.StringUtils; import java.io.File; -import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.*; import java.util.regex.Matcher; @@ -47,16 +47,16 @@ public class ResolverCache extends io.swagger.v3.parser.ResolverCache { private static final Pattern CALLBACKS_PATTERN = Pattern.compile("^" + RefType.COMPONENTS.getInternalPrefix() + "callbacks/(?.+)"); private static final Pattern HEADERS_PATTERN = Pattern.compile("^" + RefType.COMPONENTS.getInternalPrefix() + "headers/(?.+)"); private static final Pattern SECURITY_SCHEMES = Pattern.compile("^" + RefType.COMPONENTS.getInternalPrefix() + "securitySchemes/(?.+)"); - private static final Pattern PATHS_PATTERN = Pattern.compile("^" + RefType.PATH.getInternalPrefix() + "(?.+)"); + private static final Pattern PATHS_PATTERN = Pattern.compile("^" + RefType.PATH.getInternalPrefix() + "(?.+)"); private final OpenAPI openApi; private final List auths; private final Path parentDirectory; private final String rootPath; - private Map resolutionCache = new HashMap<>(); - private Map externalFileCache = new HashMap<>(); - private List referencedModelKeys = new ArrayList<>(); - private Set resolveValidationMessages; + private final Map resolutionCache = new HashMap<>(); + private final Map externalFileCache = new HashMap<>(); + private final List referencedModelKeys = new ArrayList<>(); + private final Set resolveValidationMessages; private final ParseOptions parseOptions; private final DeserializerProvider provider; protected boolean openapi31; @@ -65,7 +65,7 @@ public class ResolverCache extends io.swagger.v3.parser.ResolverCache { * a map that stores original external references, and their associated renamed * references */ - private Map renameCache = new HashMap<>(); + private final Map renameCache = new HashMap<>(); public ResolverCache(OpenAPI openApi, List auths, String parentFileLocation, DeserializerProvider provider) { this(openApi, auths, parentFileLocation, new HashSet<>(), provider); @@ -199,7 +199,7 @@ else if (rootPath != null) { } else { if (expectedType.equals(Schema.class)) { OpenAPIDeserializer deserializer = provider.deserializer(); - result = (T) deserializer.getSchema((ObjectNode) tree, definitionPath.replace("/", "."), new OpenAPIDeserializer.ParseResult().openapi31(openapi31)); + result = (T) deserializer.getSchema(tree, definitionPath.replace("/", "."), new OpenAPIDeserializer.ParseResult().openapi31(openapi31)); } else { result = DeserializationUtils.deserialize(tree, file, expectedType, openapi31); } @@ -219,7 +219,7 @@ private T deserializeFragment(JsonNode node, Class expectedType, String f OpenAPIDeserializer.ParseResult parseResult = new OpenAPIDeserializer.ParseResult(); T result = null; if (expectedType.equals(Schema.class)) { - result = (T) deserializer.getSchema((ObjectNode) node, definitionPath.replace("/", "."), parseResult); + result = (T) deserializer.getSchema(node, definitionPath.replace("/", "."), parseResult); } else if (expectedType.equals(RequestBody.class)) { result = (T) deserializer.getRequestBody((ObjectNode) node, definitionPath.replace("/", "."), parseResult); } else if (expectedType.equals(ApiResponse.class)) { @@ -348,11 +348,7 @@ else if(ref.startsWith("#/components/securitySchemes")) { private String unescapePointer(String jsonPathElement) { // URL decode the fragment - try { - jsonPathElement = URLDecoder.decode(jsonPathElement, "UTF-8"); - } catch (UnsupportedEncodingException e) { - // - } + jsonPathElement = URLDecoder.decode(jsonPathElement, StandardCharsets.UTF_8); // Unescape the JSON Pointer segment using the algorithm described in RFC 6901, section 4: // https://tools.ietf.org/html/rfc6901#section-4 // First transform any occurrence of the sequence '~1' to '/' diff --git a/src/test/java/com/amartus/sonata/blender/impl/ProductSpecReaderTest.java b/src/test/java/com/amartus/sonata/blender/impl/ProductSpecReaderTest.java index 8bbdbc3..9e1f5a5 100644 --- a/src/test/java/com/amartus/sonata/blender/impl/ProductSpecReaderTest.java +++ b/src/test/java/com/amartus/sonata/blender/impl/ProductSpecReaderTest.java @@ -19,7 +19,6 @@ package com.amartus.sonata.blender.impl; import com.amartus.Utils; -import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; import org.junit.jupiter.api.Test; @@ -81,7 +80,7 @@ public void testProtectDescriptions() { var schemas = new ProductSpecReader("testToAugment", dirPath.resolve(name)) .readSchemas(); singleRootSchema(schemas); - var root = (ObjectSchema) ((ComposedSchema) schemas.get(name)).getAllOf().get(1); + var root = (ObjectSchema) schemas.get(name).getAllOf().get(1); root.getProperties().forEach((k,v) -> { assertNotNull(v.getDescription()); }); diff --git a/src/test/java/com/amartus/sonata/blender/impl/ValidateSpecificationTest.java b/src/test/java/com/amartus/sonata/blender/impl/ValidateSpecificationTest.java index 86f0416..651df23 100644 --- a/src/test/java/com/amartus/sonata/blender/impl/ValidateSpecificationTest.java +++ b/src/test/java/com/amartus/sonata/blender/impl/ValidateSpecificationTest.java @@ -11,6 +11,7 @@ import java.util.Locale; import java.util.stream.Stream; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; public class ValidateSpecificationTest { @@ -19,10 +20,15 @@ public void smokeTest() throws Exception { var source = Paths.get(ValidateSpecificationTest.class.getResource("/oas/test-spec.yaml").toURI()); var target = Files.createTempDirectory("oas").resolve("output.yaml"); + var api = source.toAbsolutePath(); + var search = api.getParent(); + Stream args = Stream.of( "blend", "-i", - source.toAbsolutePath().toString(), + api.toString(), + "-d", + search.toString(), "--model-name", "Placeholder", "--all-schemas", @@ -48,6 +54,10 @@ public void smokeTest() throws Exception { builder.build().parse(args.toArray(String[]::new)).run(); var generated = SerializationUtils.yamlMapper().readTree(target.toFile()); + var toInject = generated.get("components").get("schemas").get("ToInject"); + assertNotNull(toInject, "toInject.json added"); + var bProp = toInject.get("allOf").get(1).get("properties").get("b"); + assertTrue(bProp.has("description"), "b property should have a description"); var messages = SpecValidator.fromClasspath().validate(generated); assertTrue(messages.isEmpty()); diff --git a/src/test/java/com/amartus/sonata/blender/impl/specifications/UrnBasedNamingStrategyTest.java b/src/test/java/com/amartus/sonata/blender/impl/specifications/UrnBasedNamingStrategyTest.java index 28127d9..78d9bb1 100644 --- a/src/test/java/com/amartus/sonata/blender/impl/specifications/UrnBasedNamingStrategyTest.java +++ b/src/test/java/com/amartus/sonata/blender/impl/specifications/UrnBasedNamingStrategyTest.java @@ -32,7 +32,7 @@ class UrnBasedNamingStrategyTest { - private ObjectMapper mapper = new ObjectMapper(); + private final ObjectMapper mapper = new ObjectMapper(); private ProductSpecificationNamingStrategy strategy; diff --git a/src/test/resources/oas/test-spec.yaml b/src/test/resources/oas/test-spec.yaml index 7a6f83f..6ae5645 100644 --- a/src/test/resources/oas/test-spec.yaml +++ b/src/test/resources/oas/test-spec.yaml @@ -62,85 +62,9 @@ paths: schema: $ref: '#/components/schemas/Error400' description: Bad Request - summary: List or find ProductOrder objects + summary: Example tags: - - productOrder - post: - description: This operation creates a ProductOrder entity. - operationId: createProductOrder - parameters: - - description: >- - The unique identifier of the organization that is acting as the a - Buyer. MUST be specified in the request only when the requester - represents more than one Buyer. - - Reference: MEF 57.2 (Sn 9.18) - in: query - name: buyerId - schema: - type: string - - description: >- - The unique identifier of the organization that is acting as the - Seller. MUST be specified in the request only when the responding - entity represents more than one Seller. - - Reference: MEF 57.2 (Sn 9.18) - in: query - name: sellerId - schema: - type: string - requestBody: - content: - application/json;charset=utf-8: - schema: - $ref: '#/components/schemas/ProductOrder_Create' - description: The ProductOrder to be created - required: true - responses: - '201': - content: - application/json;charset=utf-8: - schema: - $ref: '#/components/schemas/ProductOrder' - description: - 'Created (https://tools.ietf.org/html/rfc7231#section-6.3.2)' - '400': - content: - application/json;charset=utf-8: - schema: - $ref: '#/components/schemas/Error400' - description: Bad Request - '401': - content: - application/json;charset=utf-8: - schema: - $ref: '#/components/schemas/Error401' - description: Unauthorized - '403': - content: - application/json;charset=utf-8: - schema: - $ref: '#/components/schemas/Error403' - description: Forbidden - '422': - content: - application/json;charset=utf-8: - schema: - items: - $ref: '#/components/schemas/Error422' - type: array - description: - Unprocessable entity due to the business validation problems - '500': - content: - application/json;charset=utf-8: - schema: - $ref: '#/components/schemas/Error500' - description: Internal Server Error - summary: Creates a ProductOrder - tags: - - productOrder - x-codegen-request-body-name: productOrder + - test components: schemas: Duration: @@ -213,15 +137,6 @@ components: required: - '@type' type: object - - State: - description: | - Possible values - enum: - - a - - b - - c - type: string SomePayload: description: >- Structure to define GET without id response. A list of productOrder @@ -242,14 +157,10 @@ components: Unique identifier type: string duration: + description: This is duration $ref: '#/components/schemas/Duration' - state: - $ref: '#/components/schemas/State' - description: >- - The states as defined by TMF622 and extended to meet MEF - requirements. These states are used to convey the Product Order - status during the lifecycle of the Product Order. configuration: + description: This is configuration $ref: "#/components/schemas/Placeholder" required: - id @@ -257,187 +168,6 @@ components: - orderVersion - state type: object - ProductOrder_Update: - description: - A request initiated by the Buyer to update Product Order and/or Product - properties: - externalId: - description: - An identifier for this Product Order within the Buyer's enterprise. - type: string - note: - description: > - Free form text to clarify or explain the Product Order. Only new - notes can be entered. The Buyer and Seller cannot modify an - existing Note. The Buyer creates a Note when creating the Product - Order or when updating it. The Seller may add notes at any time. - items: - $ref: '#/components/schemas/Note' - type: array - orderVersion: - description: >- - The version of the Product Order. The `orderVersion` attribute - cannot be updated. It is used only to identify the version of the - Product Order that the Buyer wants to update. If there is a - mismatch with the Seller's system, the Seller will reject the - request with an error response. - type: string - productOrderItem: - description: | - Order Item attributes that may be updated - items: - $ref: '#/components/schemas/MEFProductOrderItem_Update' - type: array - projectId: - description: >- - An identifier that is used to group Product Orders that is - important to the Buyer. A projectId can be used to relate multiple - Product Orders together. - type: string - relatedContactInformation: - description: > - Contact information of an individual or organization playing a role - in this context. The Buyer is allowed to update the Product Order - Contact: role=productOrderContact; - items: - $ref: '#/components/schemas/RelatedContactInformation' - minItems: 1 - type: array - required: - - orderVersion - type: object - ProductRelationship: - description: >- - A relationship to an existing Product. The requirements for usage for - given Product are described in the Product Specification. - properties: - href: - description: >- - Hyperlink to the product in Seller's inventory that is referenced - Hyperlink MAY be used when providing a response by the Seller - Hyperlink MUST be ignored by the Seller in case it is provided by - the Buyer in a request - type: string - id: - description: unique identifier of the related Product - type: string - relationshipType: - description: > - Specifies the type (nature) of the relationship to the related - Product. The nature of required relationships varies for Products - of different types. For example, a UNI or ENNI Product may not have - any relationships, but an Access E-Line may have two mandatory - relationships (related to the UNI on one end and the ENNI on the - other). More complex Products such as multipoint IP or Firewall - Products may have more complex relationships. As a result, the - allowed and mandatory `relationshipType` values are defined in the - Product Specification. - type: string - required: - - id - - relationshipType - type: object - RelatedContactInformation: - description: | - Contact information of an individual or organization playing a role for - this Order Item. The rule for mapping a represented attribute value to a - `role` is to use the _lowerCamelCase_ pattern e.g. - - Buyer Order Item Contact: `role=buyerOrderItemContact` - - Buyer Implementation Contact: `role=buyerImplementationContact` - - Buyer Technical Contact: `role=buyerTechnicalContact` - properties: - emailAddress: - description: Email address - type: string - name: - description: Name of the contact - type: string - number: - description: Phone number - type: string - numberExtension: - description: Phone number extension - type: string - organization: - description: The organization or company that the contact belongs to - type: string - postalAddress: - $ref: '#/components/schemas/FieldedAddress' - description: >- - Identifies the postal address of the person or office to be - contacted. - role: - description: A role the party plays in a given context. - type: string - required: - - emailAddress - - name - - number - - role - type: object - RelatedPlaceRefOrValue: - description: - Place defines the places where the product order must be done. - discriminator: - mapping: - FieldedAddress: '#/components/schemas/FieldedAddress' - FormattedAddress: '#/components/schemas/FormattedAddress' - GeographicAddressLabel: '#/components/schemas/GeographicAddressLabel' - GeographicAddressRef: '#/components/schemas/GeographicAddressRef' - GeographicSiteRef: '#/components/schemas/GeographicSiteRef' - MEFGeographicPoint: '#/components/schemas/MEFGeographicPoint' - propertyName: '@type' - properties: - '@schemaLocation': - description: >- - A URI to a JSON-Schema file that defines additional attributes and - relationships. May be used to define additional related place - types. Usage of this attribute must be agreed upon between Buyer - and Seller. - format: uri - type: string - '@type': - description: > - This field is used as a discriminator and is used between different - place representations. This type might discriminate for additional - related place as defined in '@schemaLocation'. - type: string - role: - description: Role of this place - type: string - required: - - '@type' - - role - type: object - TerminationError: - description: >- - This indicates an error that caused an Item to be terminated. The code - and propertyPath should be used like in Error422. - properties: - code: - $ref: '#/components/schemas/Error422Code' - description: | - One of the following error codes: - - missingProperty: The property the Seller has expected is not present in the payload - - invalidValue: The property has an incorrect value - - invalidFormat: The property value does not comply with the expected value format - - referenceNotFound: The object referenced by the property cannot be identified in the Seller system - - unexpectedProperty: Additional property, not expected by the Seller has been provided - - tooManyRecords: the number of records to be provided in the response exceeds the Seller's threshold. - - otherIssue: Other problem was identified (detailed information provided in a reason) - propertyPath: - description: > - A pointer to a particular property of the payload that caused the - validation issue. It is highly recommended that this property - should be used. - - Defined using JavaScript Object Notation (JSON) Pointer - (https://tools.ietf.org/html/rfc6901). - type: string - value: - description: Text to describe the reason of the termination. - type: string - type: object TimeUnit: description: | Represents a unit of time. diff --git a/src/test/resources/oas/toInject.json b/src/test/resources/oas/toInject.json new file mode 100644 index 0000000..560eee2 --- /dev/null +++ b/src/test/resources/oas/toInject.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "urn:mef:lso:spec:cantata-sonata:to-inject:v0.3.0:all", + "description": "To inject description", + "properties": { + "a": { + "description": "A description", + "type": "string" + }, + "b": { + "description": "B description", + "$ref": "#/definitions/FooBar" + } + }, + "definitions": { + "FooBar": { + "properties": { + "foo": { + "type": "string" + } + } + } + } +} \ No newline at end of file