Skip to content

Commit 43557c5

Browse files
committed
refs #2340 - add JsonTypeInfo.property to schema if not existing
1 parent 5baf7c6 commit 43557c5

File tree

5 files changed

+141
-4
lines changed

5 files changed

+141
-4
lines changed

modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,9 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
840840
}
841841
}
842842
}
843+
844+
resolveDiscriminatorProperty(type, context, model);
845+
843846
return model;
844847
}
845848

@@ -1624,6 +1627,27 @@ protected Map<String, Object> resolveExtensions(Annotated a, Annotation[] annota
16241627
return null;
16251628
}
16261629

1630+
protected void resolveDiscriminatorProperty(JavaType type, ModelConverterContext context, Schema model) {
1631+
// add JsonTypeInfo.property if not member of bean
1632+
JsonTypeInfo typeInfo = type.getRawClass().getDeclaredAnnotation(JsonTypeInfo.class);
1633+
if (typeInfo != null) {
1634+
String typeInfoProp = typeInfo.property();
1635+
if (StringUtils.isNotBlank(typeInfoProp)) {
1636+
Schema modelToUpdate = model;
1637+
if (StringUtils.isNotBlank(model.get$ref())) {
1638+
modelToUpdate = context.getDefinedModels().get(model.get$ref().substring(21));
1639+
}
1640+
if (modelToUpdate.getProperties() == null || !modelToUpdate.getProperties().keySet().contains(typeInfoProp)) {
1641+
Schema discriminatorSchema = new StringSchema().name(typeInfoProp);
1642+
modelToUpdate.addProperties(typeInfoProp, discriminatorSchema);
1643+
if (modelToUpdate.getRequired() == null || !model.getRequired().contains(typeInfoProp)) {
1644+
modelToUpdate.addRequiredItem(typeInfoProp);
1645+
}
1646+
}
1647+
}
1648+
}
1649+
}
1650+
16271651
protected Discriminator resolveDiscriminator(JavaType type, ModelConverterContext context) {
16281652

16291653
io.swagger.v3.oas.annotations.media.Schema declaredSchemaAnnotation = AnnotationsUtils.getSchemaDeclaredAnnotation(type.getRawClass());

modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/InheritedBeanTest.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping;
1010
import io.swagger.v3.oas.models.media.ComposedSchema;
1111
import io.swagger.v3.oas.models.media.Schema;
12-
import org.testng.annotations.BeforeTest;
12+
import org.testng.annotations.AfterTest;
13+
import org.testng.annotations.BeforeMethod;
1314
import org.testng.annotations.Test;
1415

1516
import java.util.Map;
@@ -23,12 +24,18 @@ public class InheritedBeanTest extends SwaggerTestBase {
2324
private ModelResolver modelResolver;
2425
private ModelConverterContextImpl context;
2526

26-
@BeforeTest
27+
@BeforeMethod
2728
public void setup() {
29+
ModelResolver.composedModelPropertiesAsSibling = false;
2830
modelResolver = new ModelResolver(new ObjectMapper());
2931
context = new ModelConverterContextImpl(modelResolver);
3032
}
3133

34+
@AfterTest
35+
public void afterTest() {
36+
ModelResolver.composedModelPropertiesAsSibling = false;
37+
}
38+
3239
@Test
3340
public void testInheritedBean() throws Exception {
3441
final Schema baseModel = context.resolve(new AnnotatedType(BaseBean.class));

modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket3197Test.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,14 @@ public void testTicket3197() throws Exception {
3939
final Schema model = context.resolve(new AnnotatedType(Car.class));
4040
assertNotNull(model);
4141
String yaml = "Car:\n" +
42+
" required:\n" +
43+
" - type\n" +
4244
" type: object\n" +
4345
" properties:\n" +
4446
" carMetaData:\n" +
4547
" type: string\n" +
48+
" type:\n" +
49+
" type: string\n" +
4650
" discriminator:\n" +
4751
" propertyName: type\n" +
4852
" mapping:\n" +
@@ -77,7 +81,7 @@ public void testTicket3197() throws Exception {
7781
" type: integer\n" +
7882
" format: int64\n" +
7983
" model:\n" +
80-
" type: string";
84+
" type: string\n";
8185

8286
SerializationMatchers.assertEqualsToYaml(context.getDefinedModels(), yaml);
8387
}
@@ -87,15 +91,20 @@ public void testTicket3197AsSibling() throws Exception {
8791

8892
ModelResolver.composedModelPropertiesAsSibling = true;
8993
ModelResolver myModelResolver = new ModelResolver(new ObjectMapper());
94+
ModelResolver.composedModelPropertiesAsSibling = true;
9095
ModelConverterContextImpl myContext = new ModelConverterContextImpl(myModelResolver);
9196

9297
final Schema model = myContext.resolve(new AnnotatedType(Car.class));
9398
assertNotNull(model);
9499
String yaml = "Car:\n" +
100+
" required:\n" +
101+
" - type\n" +
95102
" type: object\n" +
96103
" properties:\n" +
97104
" carMetaData:\n" +
98105
" type: string\n" +
106+
" type:\n" +
107+
" type: string\n" +
99108
" discriminator:\n" +
100109
" propertyName: type\n" +
101110
" mapping:\n" +
@@ -128,7 +137,7 @@ public void testTicket3197AsSibling() throws Exception {
128137
" model:\n" +
129138
" type: string\n" +
130139
" allOf:\n" +
131-
" - $ref: '#/components/schemas/Car'";
140+
" - $ref: '#/components/schemas/Car'\n";
132141

133142
SerializationMatchers.assertEqualsToYaml(myContext.getDefinedModels(), yaml);
134143
ModelResolver.composedModelPropertiesAsSibling = false;

modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import io.swagger.v3.jaxrs2.resources.TagsResource;
5252
import io.swagger.v3.jaxrs2.resources.Test2607;
5353
import io.swagger.v3.jaxrs2.resources.TestResource;
54+
import io.swagger.v3.jaxrs2.resources.Ticket2340Resource;
5455
import io.swagger.v3.jaxrs2.resources.Ticket2644ConcreteImplementation;
5556
import io.swagger.v3.jaxrs2.resources.Ticket2763Resource;
5657
import io.swagger.v3.jaxrs2.resources.Ticket2793Resource;
@@ -993,6 +994,55 @@ public void testTicket2763() {
993994
SerializationMatchers.assertEqualsToYaml(openAPI, yaml);
994995
}
995996

997+
@Test(description = "Responses with array schema")
998+
public void testTicket2340() {
999+
Reader reader = new Reader(new OpenAPI());
1000+
1001+
OpenAPI openAPI = reader.read(Ticket2340Resource.class);
1002+
String yaml = "openapi: 3.0.1\n" +
1003+
"paths:\n" +
1004+
" /test/test:\n" +
1005+
" post:\n" +
1006+
" operationId: getBook\n" +
1007+
" responses:\n" +
1008+
" default:\n" +
1009+
" description: default response\n" +
1010+
" content:\n" +
1011+
" application/json:\n" +
1012+
" schema:\n" +
1013+
" type: string\n" +
1014+
"components:\n" +
1015+
" schemas:\n" +
1016+
" Animal:\n" +
1017+
" required:\n" +
1018+
" - type\n" +
1019+
" type: object\n" +
1020+
" properties:\n" +
1021+
" type:\n" +
1022+
" type: string\n" +
1023+
" discriminator:\n" +
1024+
" propertyName: type\n" +
1025+
" Cat:\n" +
1026+
" type: object\n" +
1027+
" allOf:\n" +
1028+
" - $ref: '#/components/schemas/Animal'\n" +
1029+
" - type: object\n" +
1030+
" properties:\n" +
1031+
" lives:\n" +
1032+
" type: integer\n" +
1033+
" format: int32\n" +
1034+
" Dog:\n" +
1035+
" type: object\n" +
1036+
" allOf:\n" +
1037+
" - $ref: '#/components/schemas/Animal'\n" +
1038+
" - type: object\n" +
1039+
" properties:\n" +
1040+
" barkVolume:\n" +
1041+
" type: number\n" +
1042+
" format: double\n";
1043+
SerializationMatchers.assertEqualsToYaml(openAPI, yaml);
1044+
}
1045+
9961046
@Test(description = "array schema example")
9971047
public void testTicket2806() {
9981048
Reader reader = new Reader(new OpenAPI());
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.swagger.v3.jaxrs2.resources;
2+
3+
import com.fasterxml.jackson.annotation.JsonSubTypes;
4+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
5+
import com.fasterxml.jackson.annotation.JsonTypeName;
6+
import io.swagger.v3.oas.annotations.parameters.RequestBody;
7+
8+
import javax.ws.rs.POST;
9+
import javax.ws.rs.Path;
10+
import javax.ws.rs.Produces;
11+
import javax.ws.rs.core.MediaType;
12+
13+
@Path("/test")
14+
public class Ticket2340Resource {
15+
16+
@Produces({ MediaType.APPLICATION_JSON })
17+
@Path("/test")
18+
@POST
19+
public String getBook(@RequestBody Animal animal) {
20+
return "ok";
21+
}
22+
23+
24+
@JsonTypeInfo(
25+
use = JsonTypeInfo.Id.NAME,
26+
include = JsonTypeInfo.As.PROPERTY,
27+
property = "type")//, visible = true)
28+
@JsonSubTypes({
29+
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
30+
@JsonSubTypes.Type(value = Cat.class, name = "cat")
31+
})
32+
public static class Animal {
33+
//public String type;
34+
}
35+
36+
@JsonTypeName("dog")
37+
public static class Dog extends Animal {
38+
public double barkVolume;
39+
}
40+
41+
@JsonTypeName("cat")
42+
public static class Cat extends Animal {
43+
boolean likesCream;
44+
public int lives;
45+
}
46+
47+
}

0 commit comments

Comments
 (0)