diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java index 12cec2add..1673ce8a1 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java @@ -21,7 +21,7 @@ * * * * * * * * * - * + * */ package org.springdoc.core.converters; @@ -110,32 +110,35 @@ else if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSi @Override public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) { JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType()); - if (javaType != null) { - for (Field field : FieldUtils.getAllFields(javaType.getRawClass())) { - if (field.isAnnotationPresent(JsonUnwrapped.class)) { - PARENT_TYPES_TO_IGNORE.add(javaType.getRawClass().getSimpleName()); - } + + if (javaType == null || !chain.hasNext()) { + return null; + } + + for (Field field : FieldUtils.getAllFields(javaType.getRawClass())) { + if (field.isAnnotationPresent(JsonUnwrapped.class)) { + PARENT_TYPES_TO_IGNORE.add(javaType.getRawClass().getSimpleName()); } - if (chain.hasNext()) { - if (!type.isResolveAsRef() && type.getParent() != null - && PARENT_TYPES_TO_IGNORE.stream().noneMatch(ignore -> type.getParent().getName().startsWith(ignore))) - type.resolveAsRef(true); - Schema resolvedSchema = chain.next().resolve(type, context, chain); - resolvedSchema = getResolvedSchema(javaType, resolvedSchema); - if (resolvedSchema == null || resolvedSchema.get$ref() == null) { - return resolvedSchema; - } - if(resolvedSchema.get$ref().contains(Components.COMPONENTS_SCHEMAS_REF)) { - String schemaName = resolvedSchema.get$ref().substring(Components.COMPONENTS_SCHEMAS_REF.length()); - Schema existingSchema = context.getDefinedModels().get(schemaName); - if (existingSchema != null && existingSchema.getOneOf() != null) { - return resolvedSchema; - } - } - return composePolymorphicSchema(type, resolvedSchema, context.getDefinedModels().values()); + } + + String parentName = type.getParent() == null ? null : type.getParent().getName(); + if (parentName != null && PARENT_TYPES_TO_IGNORE.stream().noneMatch(parentName::startsWith)){ + type.resolveAsRef(true); + } + + Schema resolvedSchema = getResolvedSchema(javaType, chain.next().resolve(type, context, chain)); + if (resolvedSchema == null || resolvedSchema.get$ref() == null) { + return resolvedSchema; + } + + if(resolvedSchema.get$ref().contains(Components.COMPONENTS_SCHEMAS_REF)) { + String schemaName = resolvedSchema.get$ref().substring(Components.COMPONENTS_SCHEMAS_REF.length()); + Schema existingSchema = context.getDefinedModels().get(schemaName); + if (existingSchema != null && (existingSchema.getOneOf() != null || existingSchema.getAllOf() != null || existingSchema.getAnyOf() != null)) { + return resolvedSchema; } } - return null; + return composePolymorphicSchema(type, resolvedSchema, context.getDefinedModels().values()); } /** diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app13/SpringDocApp13Test.kt b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app13/SpringDocApp13Test.kt new file mode 100644 index 000000000..1f2f41145 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app13/SpringDocApp13Test.kt @@ -0,0 +1,49 @@ +/* + * + * * Copyright 2019-2020 the original author or authors. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * https://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package test.org.springdoc.api.app13 + +import org.springdoc.core.properties.SpringDocConfigProperties +import org.springdoc.core.properties.SpringDocConfigProperties.ApiDocs.OpenApiVersion +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import test.org.springdoc.api.AbstractKotlinSpringDocMVCTest + + +@SpringBootTest//(classes = [Config::class]) +class SpringDocApp13Test : AbstractKotlinSpringDocMVCTest() { + + + @Configuration + class Config{ + @Bean + fun springDocConfigProperties():SpringDocConfigProperties{ + val x= SpringDocConfigProperties() + x.apiDocs.version = OpenApiVersion.OPENAPI_3_1 + return x + } + + } + + + @SpringBootApplication + class DemoApplication + +} diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app13/TestController.kt b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app13/TestController.kt new file mode 100644 index 000000000..7ec21bac8 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app13/TestController.kt @@ -0,0 +1,51 @@ +/* + * + * * Copyright 2019-2020 the original author or authors. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * https://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package test.org.springdoc.api.app13 + + +import io.swagger.v3.oas.annotations.OpenAPI31 +import io.swagger.v3.oas.annotations.media.Schema +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@Schema(description = "Generic description") +data class KeyValue( + val key: String, + val value: String, +) + +@Schema +data class SomeDTO( + @Schema(description = "Description A") val fieldA: KeyValue, + @Schema(description = "Description B") val fieldB: KeyValue, +) + + + +@RestController +@RequestMapping("/test") +class TestController { + @PostMapping("/test") + fun create(@RequestBody some: SomeDTO) { + + } +} + diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/app13.json b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/app13.json new file mode 100644 index 000000000..6bf07eb5b --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/app13.json @@ -0,0 +1,68 @@ +{ + "openapi" : "3.1.0", + "info" : { + "title" : "OpenAPI definition", + "version" : "v0" + }, + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/test/test" : { + "post" : { + "tags" : [ "test-controller" ], + "operationId" : "create", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SomeDTO" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "description" : "OK" + } + } + } + } + }, + "components" : { + "schemas" : { + "KeyValue" : { + "required" : [ "key", "value" ], + "type" : "object", + "description" : "Generic description", + "properties" : { + "key" : { + "type" : "string" + }, + "value" : { + "type" : "string" + } + } + }, + "SomeDTO" : { + "required": [ + "fieldA", + "fieldB" + ], + "type": "object", + "properties": { + "fieldA": { + "description": "Description A", + "$ref": "#/components/schemas/KeyValue" + }, + "fieldB": { + "description": "Description B", + "$ref": "#/components/schemas/KeyValue" + } + } + } + } + } +} \ No newline at end of file