From 24785165dbacd61df1d874060e50372e74d49c47 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 20 Aug 2022 04:19:04 +0200 Subject: [PATCH] Polymorphism - documentation not generated for subtypes when using JsonTypeInfo.As.WRAPPER_OBJECT and JsonTypeInfo.Id.NAME. fixes #1799 --- CHANGELOG.md | 2 +- .../converters/PolymorphicModelConverter.java | 17 +++- .../api/v30/app192/SpringDocApp192Test.java | 9 +- .../org/springdoc/api/v30/app193/Animal.java | 17 ++++ .../api/v30/app193/BasicController.java | 21 +++++ .../org/springdoc/api/v30/app193/Cat.java | 22 +++++ .../org/springdoc/api/v30/app193/Dog.java | 32 +++++++ .../SpringDocApp193Test.java} | 16 ++-- .../test/resources/results/3.0.1/app193.json | 91 +++++++++++++++++++ 9 files changed, 214 insertions(+), 13 deletions(-) create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Animal.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/BasicController.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Cat.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Dog.java rename springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/{app192/SpringDocTestApp.java => app193/SpringDocApp193Test.java} (77%) create mode 100644 springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app193.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f97df486..8a4f076b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #1692 - More specific bean name for objectMapperProvider - #1684 - Incorrect generic param for multi interfaces - #1707 - Concurrent problems when initializing multiple GroupedOpenApi parallelly -- 1690 - Expected file to be in alphabetical order. +- #1690 - Expected file to be in alphabetical order. - #1713 - ObjectMapperProvider to sort all properties. - #1717, #1718 - javadoc of JsonUnwrapped fields not set - #1748, #1712, Generated server url computation not cleared diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java index c421738eb..796957c63 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java @@ -34,6 +34,7 @@ import io.swagger.v3.core.converter.ModelConverterContext; import io.swagger.v3.core.util.AnnotationsUtils; 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.springdoc.core.providers.ObjectMapperProvider; @@ -48,6 +49,7 @@ public class PolymorphicModelConverter implements ModelConverter { */ private final ObjectMapperProvider springDocObjectMapper; + /** * Instantiates a new Polymorphic model converter. * @@ -59,10 +61,17 @@ public PolymorphicModelConverter(ObjectMapperProvider springDocObjectMapper) { @Override public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) { - if (chain.hasNext()) { - Schema resolvedSchema = chain.next().resolve(type, context, chain); - if (resolvedSchema == null || resolvedSchema.get$ref() == null) return resolvedSchema; - return composePolymorphicSchema(type, resolvedSchema, context.getDefinedModels().values()); + JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType()); + if (javaType != null) { + if (chain.hasNext()) { + Schema resolvedSchema = chain.next().resolve(type, context, chain); + if (resolvedSchema instanceof ObjectSchema && resolvedSchema.getProperties() != null + && resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSimpleName())) + resolvedSchema = resolvedSchema.getProperties().get(javaType.getRawClass().getSimpleName()); + if (resolvedSchema == null || resolvedSchema.get$ref() == null) + return resolvedSchema; + return composePolymorphicSchema(type, resolvedSchema, context.getDefinedModels().values()); + } } return null; } diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocApp192Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocApp192Test.java index 61153491e..d9a84c3df 100644 --- a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocApp192Test.java +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocApp192Test.java @@ -25,5 +25,12 @@ import test.org.springdoc.api.v30.AbstractSpringDocV30Test; +import org.springframework.boot.autoconfigure.SpringBootApplication; -public class SpringDocApp192Test extends AbstractSpringDocV30Test { } + +public class SpringDocApp192Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} + +} \ No newline at end of file diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Animal.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Animal.java new file mode 100644 index 000000000..726540e34 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Animal.java @@ -0,0 +1,17 @@ +package test.org.springdoc.api.v30.app193; + + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Interface of the Animal. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) +@JsonSubTypes({ + @JsonSubTypes.Type(value = Dog.class, name = "dog"), + @JsonSubTypes.Type(value = Cat.class, name = "cat"), +}) +@Schema(description = "Represents an Animal class.") +public interface Animal {} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/BasicController.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/BasicController.java new file mode 100644 index 000000000..c8f4d9dc7 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/BasicController.java @@ -0,0 +1,21 @@ +package test.org.springdoc.api.v30.app193; + +import io.swagger.v3.oas.annotations.Operation; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(path = "/") +public class BasicController { + + @GetMapping("/test") + @Operation(summary = "get", description = "Provides an animal.") + public Animal get() { + + return new Dog("Foo", 12); + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Cat.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Cat.java new file mode 100644 index 000000000..b624da00f --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Cat.java @@ -0,0 +1,22 @@ +package test.org.springdoc.api.v30.app193; + + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Represents a Cat class.") +public class Cat implements Animal { + + private Integer speed; + + public Cat(Integer speed) { + this.speed = speed; + } + + public Integer getSpeed() { + return speed; + } + + public void setSpeed(Integer speed) { + this.speed = speed; + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Dog.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Dog.java new file mode 100644 index 000000000..78ccdfa8a --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/Dog.java @@ -0,0 +1,32 @@ +package test.org.springdoc.api.v30.app193; + + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Represents a Dog class.") +public class Dog implements Animal { + + private String name; + private Integer age; + + public Dog(String name, Integer age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocTestApp.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/SpringDocApp193Test.java similarity index 77% rename from springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocTestApp.java rename to springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/SpringDocApp193Test.java index 4a9ed139b..c0b0c0f38 100644 --- a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocTestApp.java +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/SpringDocApp193Test.java @@ -20,15 +20,17 @@ * */ -package test.org.springdoc.api.v30.app192; +package test.org.springdoc.api.v30.app193; + + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; -import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -@SpringBootApplication -public class SpringDocTestApp { - public static void main(String[] args) { - SpringApplication.run(SpringDocTestApp.class, args); - } +public class SpringDocApp193Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} + } diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app193.json b/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app193.json new file mode 100644 index 000000000..8c576db5e --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app193.json @@ -0,0 +1,91 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/test": { + "get": { + "tags": [ + "basic-controller" + ], + "summary": "get", + "description": "Provides an animal.", + "operationId": "get", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ] + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Animal": { + "type": "object", + "description": "Represents an Animal class." + }, + "Cat": { + "type": "object", + "description": "Represents a Cat class.", + "allOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "speed": { + "type": "integer", + "format": "int32" + } + } + } + ] + }, + "Dog": { + "type": "object", + "description": "Represents a Dog class.", + "allOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer", + "format": "int32" + } + } + } + ] + } + } + } +}