Skip to content

Commit 2478516

Browse files
committed
Polymorphism - documentation not generated for subtypes when using JsonTypeInfo.As.WRAPPER_OBJECT and JsonTypeInfo.Id.NAME. fixes #1799
1 parent 2272cb3 commit 2478516

File tree

9 files changed

+214
-13
lines changed

9 files changed

+214
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424
- #1692 - More specific bean name for objectMapperProvider
2525
- #1684 - Incorrect generic param for multi interfaces
2626
- #1707 - Concurrent problems when initializing multiple GroupedOpenApi parallelly
27-
- 1690 - Expected file to be in alphabetical order.
27+
- #1690 - Expected file to be in alphabetical order.
2828
- #1713 - ObjectMapperProvider to sort all properties.
2929
- #1717, #1718 - javadoc of JsonUnwrapped fields not set
3030
- #1748, #1712, Generated server url computation not cleared

springdoc-openapi-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import io.swagger.v3.core.converter.ModelConverterContext;
3535
import io.swagger.v3.core.util.AnnotationsUtils;
3636
import io.swagger.v3.oas.models.media.ComposedSchema;
37+
import io.swagger.v3.oas.models.media.ObjectSchema;
3738
import io.swagger.v3.oas.models.media.Schema;
3839
import org.springdoc.core.providers.ObjectMapperProvider;
3940

@@ -48,6 +49,7 @@ public class PolymorphicModelConverter implements ModelConverter {
4849
*/
4950
private final ObjectMapperProvider springDocObjectMapper;
5051

52+
5153
/**
5254
* Instantiates a new Polymorphic model converter.
5355
*
@@ -59,10 +61,17 @@ public PolymorphicModelConverter(ObjectMapperProvider springDocObjectMapper) {
5961

6062
@Override
6163
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
62-
if (chain.hasNext()) {
63-
Schema<?> resolvedSchema = chain.next().resolve(type, context, chain);
64-
if (resolvedSchema == null || resolvedSchema.get$ref() == null) return resolvedSchema;
65-
return composePolymorphicSchema(type, resolvedSchema, context.getDefinedModels().values());
64+
JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType());
65+
if (javaType != null) {
66+
if (chain.hasNext()) {
67+
Schema<?> resolvedSchema = chain.next().resolve(type, context, chain);
68+
if (resolvedSchema instanceof ObjectSchema && resolvedSchema.getProperties() != null
69+
&& resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSimpleName()))
70+
resolvedSchema = resolvedSchema.getProperties().get(javaType.getRawClass().getSimpleName());
71+
if (resolvedSchema == null || resolvedSchema.get$ref() == null)
72+
return resolvedSchema;
73+
return composePolymorphicSchema(type, resolvedSchema, context.getDefinedModels().values());
74+
}
6675
}
6776
return null;
6877
}

springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocApp192Test.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,12 @@
2525

2626
import test.org.springdoc.api.v30.AbstractSpringDocV30Test;
2727

28+
import org.springframework.boot.autoconfigure.SpringBootApplication;
2829

29-
public class SpringDocApp192Test extends AbstractSpringDocV30Test { }
30+
31+
public class SpringDocApp192Test extends AbstractSpringDocV30Test {
32+
33+
@SpringBootApplication
34+
static class SpringDocTestApp {}
35+
36+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package test.org.springdoc.api.v30.app193;
2+
3+
4+
import com.fasterxml.jackson.annotation.JsonSubTypes;
5+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
8+
/**
9+
* Interface of the Animal.
10+
*/
11+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
12+
@JsonSubTypes({
13+
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
14+
@JsonSubTypes.Type(value = Cat.class, name = "cat"),
15+
})
16+
@Schema(description = "Represents an Animal class.")
17+
public interface Animal {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package test.org.springdoc.api.v30.app193;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.ResponseStatus;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
@RestController
12+
@RequestMapping(path = "/")
13+
public class BasicController {
14+
15+
@GetMapping("/test")
16+
@Operation(summary = "get", description = "Provides an animal.")
17+
public Animal get() {
18+
19+
return new Dog("Foo", 12);
20+
}
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package test.org.springdoc.api.v30.app193;
2+
3+
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
6+
@Schema(description = "Represents a Cat class.")
7+
public class Cat implements Animal {
8+
9+
private Integer speed;
10+
11+
public Cat(Integer speed) {
12+
this.speed = speed;
13+
}
14+
15+
public Integer getSpeed() {
16+
return speed;
17+
}
18+
19+
public void setSpeed(Integer speed) {
20+
this.speed = speed;
21+
}
22+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package test.org.springdoc.api.v30.app193;
2+
3+
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
6+
@Schema(description = "Represents a Dog class.")
7+
public class Dog implements Animal {
8+
9+
private String name;
10+
private Integer age;
11+
12+
public Dog(String name, Integer age) {
13+
this.name = name;
14+
this.age = age;
15+
}
16+
17+
public String getName() {
18+
return name;
19+
}
20+
21+
public void setName(String name) {
22+
this.name = name;
23+
}
24+
25+
public Integer getAge() {
26+
return age;
27+
}
28+
29+
public void setAge(Integer age) {
30+
this.age = age;
31+
}
32+
}

springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app192/SpringDocTestApp.java renamed to springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app193/SpringDocApp193Test.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@
2020
*
2121
*/
2222

23-
package test.org.springdoc.api.v30.app192;
23+
package test.org.springdoc.api.v30.app193;
24+
25+
26+
import test.org.springdoc.api.v30.AbstractSpringDocV30Test;
2427

25-
import org.springframework.boot.SpringApplication;
2628
import org.springframework.boot.autoconfigure.SpringBootApplication;
2729

28-
@SpringBootApplication
29-
public class SpringDocTestApp {
3030

31-
public static void main(String[] args) {
32-
SpringApplication.run(SpringDocTestApp.class, args);
33-
}
31+
public class SpringDocApp193Test extends AbstractSpringDocV30Test {
32+
33+
@SpringBootApplication
34+
static class SpringDocTestApp {}
35+
3436
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {
14+
"/test": {
15+
"get": {
16+
"tags": [
17+
"basic-controller"
18+
],
19+
"summary": "get",
20+
"description": "Provides an animal.",
21+
"operationId": "get",
22+
"responses": {
23+
"200": {
24+
"description": "OK",
25+
"content": {
26+
"*/*": {
27+
"schema": {
28+
"oneOf": [
29+
{
30+
"$ref": "#/components/schemas/Cat"
31+
},
32+
{
33+
"$ref": "#/components/schemas/Dog"
34+
}
35+
]
36+
}
37+
}
38+
}
39+
}
40+
}
41+
}
42+
}
43+
},
44+
"components": {
45+
"schemas": {
46+
"Animal": {
47+
"type": "object",
48+
"description": "Represents an Animal class."
49+
},
50+
"Cat": {
51+
"type": "object",
52+
"description": "Represents a Cat class.",
53+
"allOf": [
54+
{
55+
"$ref": "#/components/schemas/Animal"
56+
},
57+
{
58+
"type": "object",
59+
"properties": {
60+
"speed": {
61+
"type": "integer",
62+
"format": "int32"
63+
}
64+
}
65+
}
66+
]
67+
},
68+
"Dog": {
69+
"type": "object",
70+
"description": "Represents a Dog class.",
71+
"allOf": [
72+
{
73+
"$ref": "#/components/schemas/Animal"
74+
},
75+
{
76+
"type": "object",
77+
"properties": {
78+
"name": {
79+
"type": "string"
80+
},
81+
"age": {
82+
"type": "integer",
83+
"format": "int32"
84+
}
85+
}
86+
}
87+
]
88+
}
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)