Skip to content

Commit ca43c20

Browse files
committed
Keeps ModelConverterContextImpl in the ModelConverters singleton to avoid recreating and overwriting composedSchemas with normal schemas.
1 parent 09a893f commit ca43c20

File tree

9 files changed

+110
-14
lines changed

9 files changed

+110
-14
lines changed

modules/swagger-core/src/main/java/io/swagger/v3/core/converter/AnnotatedType.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.swagger.v3.core.converter;
22

33
import com.fasterxml.jackson.annotation.JsonView;
4+
import com.fasterxml.jackson.databind.type.TypeBase;
5+
46
import io.swagger.v3.oas.models.media.Schema;
57

68
import java.lang.annotation.Annotation;
@@ -11,6 +13,9 @@
1113
import java.util.Objects;
1214
import java.util.function.Function;
1315

16+
import org.apache.commons.lang3.ArrayUtils;
17+
import org.apache.commons.lang3.StringUtils;
18+
1419
public class AnnotatedType {
1520
private Type type;
1621
private String name;
@@ -157,6 +162,20 @@ public void setType(Type type) {
157162
this.type = type;
158163
}
159164

165+
/**
166+
* Get the canonical type name of the inner type.
167+
*/
168+
public String getTypeName() {
169+
Type type = this.getType();
170+
if (type instanceof TypeBase) {
171+
return ((TypeBase) type).toCanonical();
172+
} else if (type instanceof Class) {
173+
return ((Class) type).getName();
174+
} else {
175+
return null;
176+
}
177+
}
178+
160179
public AnnotatedType type(Type type) {
161180
setType(type);
162181
return this;
@@ -211,17 +230,20 @@ public boolean equals(Object o) {
211230
return false;
212231
}
213232

214-
if (type != null && that.type != null && !type.equals(that.type)) {
233+
if (type != null && that.type != null && !StringUtils.equals(that.getTypeName(), getTypeName())) {
215234
return false;
216235
}
236+
if (ArrayUtils.isEmpty(this.ctxAnnotations) && ArrayUtils.isEmpty(that.ctxAnnotations)) {
237+
return true;
238+
}
217239
return Arrays.equals(this.ctxAnnotations, that.ctxAnnotations);
218240
}
219241

220242

221243
@Override
222244
public int hashCode() {
223245
if (ctxAnnotations == null || ctxAnnotations.length == 0) {
224-
return Objects.hash(type, "fixed");
246+
return Objects.hash(getTypeName(), "fixed");
225247
}
226248
List<Annotation> meaningfulAnnotations = new ArrayList<>();
227249

@@ -234,7 +256,7 @@ public int hashCode() {
234256
}
235257
}
236258
int result = 1;
237-
result = 31 * result + (type == null ? 0 : Objects.hash(type, "fixed"));
259+
result = 31 * result + (type == null ? 0 : Objects.hash(getTypeName(), "fixed"));
238260
if (hasDifference) {
239261
result = 31 * result + (meaningfulAnnotations == null ? 0 : Arrays.hashCode(meaningfulAnnotations.toArray(new Annotation[meaningfulAnnotations.size()])));
240262
} else {

modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverterContextImpl.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,8 @@ public Schema resolve(AnnotatedType type) {
7676

7777
if (processedTypes.contains(type)) {
7878
return modelByType.get(type);
79-
} else {
80-
processedTypes.add(type);
8179
}
80+
processedTypes.add(type);
8281
if (LOGGER.isDebugEnabled()) {
8382
LOGGER.debug(String.format("resolve %s", type.getType()));
8483
}

modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,23 @@ public class ModelConverters {
2525
private final Set<String> skippedPackages = new HashSet<String>();
2626
private final Set<String> skippedClasses = new HashSet<String>();
2727

28+
private ModelConverterContextImpl context;
29+
2830
public ModelConverters() {
2931
converters = new CopyOnWriteArrayList<>();
3032
converters.add(new ModelResolver(Json.mapper()));
33+
resetContext();
34+
3135
}
3236

3337
public static ModelConverters getInstance() {
3438
return SINGLETON;
3539
}
3640

41+
public void resetContext() {
42+
context = new ModelConverterContextImpl(converters);;
43+
}
44+
3745
public void addConverter(ModelConverter converter) {
3846
converters.add(0, converter);
3947
}
@@ -92,8 +100,6 @@ public ResolvedSchema readAllAsResolvedSchema(Type type) {
92100
}
93101
public ResolvedSchema readAllAsResolvedSchema(AnnotatedType type) {
94102
if (shouldProcess(type.getType())) {
95-
ModelConverterContextImpl context = new ModelConverterContextImpl(
96-
converters);
97103

98104
ResolvedSchema resolvedSchema = new ResolvedSchema();
99105
resolvedSchema.schema = context.resolve(type);
@@ -105,8 +111,6 @@ public ResolvedSchema readAllAsResolvedSchema(AnnotatedType type) {
105111
}
106112

107113
public ResolvedSchema resolveAsResolvedSchema(AnnotatedType type) {
108-
ModelConverterContextImpl context = new ModelConverterContextImpl(
109-
converters);
110114

111115
ResolvedSchema resolvedSchema = new ResolvedSchema();
112116
resolvedSchema.schema = context.resolve(type);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,15 +424,15 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
424424
context.resolve(new AnnotatedType().type(valueType).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()));
425425
return null;
426426
}
427-
Schema items = context.resolve(new AnnotatedType()
427+
Schema items = clone(context.resolve(new AnnotatedType()
428428
.type(valueType)
429429
.schemaProperty(annotatedType.isSchemaProperty())
430430
.ctxAnnotations(schemaAnnotations)
431431
.skipSchemaName(true)
432432
.resolveAsRef(annotatedType.isResolveAsRef())
433433
.propertyName(annotatedType.getPropertyName())
434434
.jsonViewAnnotation(annotatedType.getJsonViewAnnotation())
435-
.parent(annotatedType.getParent()));
435+
.parent(annotatedType.getParent())));
436436

437437
if (items == null) {
438438
return null;

modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ public static Schema resolveSchemaFromType(Class<?> schemaImplementation, Compon
559559
schemaObject = primitiveType.createProperty();
560560
} else {
561561
schemaObject = new Schema();
562-
ResolvedSchema resolvedSchema = ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(schemaImplementation).jsonViewAnnotation(jsonViewAnnotation));
562+
ResolvedSchema resolvedSchema = ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(schemaImplementation).jsonViewAnnotation(jsonViewAnnotation).resolveAsRef(true));
563563
Map<String, Schema> schemaMap;
564564
if (resolvedSchema != null) {
565565
schemaMap = resolvedSchema.referencedSchemas;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.swagger.v3.jaxrs2;
22

3+
import io.swagger.v3.core.converter.ModelConverters;
34
import io.swagger.v3.jaxrs2.matchers.SerializationMatchers;
45
import io.swagger.v3.jaxrs2.resources.EnumParameterResource;
56
import io.swagger.v3.jaxrs2.resources.JsonIdentityCyclicResource;
@@ -13,6 +14,7 @@ public class EnumTest {
1314

1415
@Test(description = "Test enum")
1516
public void testEnum() throws IOException {
17+
ModelConverters.getInstance().resetContext();
1618
Reader reader = new Reader(new OpenAPI());
1719
OpenAPI openAPI = reader.read(EnumParameterResource.class);
1820
SerializationMatchers.assertEqualsToYaml(openAPI, EXPECTED_YAML);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.swagger.v3.jaxrs2;
22

3+
import io.swagger.v3.core.converter.ModelConverters;
34
import io.swagger.v3.jaxrs2.annotations.AbstractAnnotationTest;
45
import io.swagger.v3.jaxrs2.matchers.SerializationMatchers;
56
import io.swagger.v3.jaxrs2.petstore.EmptyPetResource;
@@ -256,6 +257,7 @@ private static List<Class> findClasses(final File directory, final String packag
256257
* @param source where is the yaml.
257258
*/
258259
private void compare(final Class clazz, final String source) {
260+
ModelConverters.getInstance().resetContext();
259261
final String file = source + clazz.getSimpleName() + YAML_EXTENSION;
260262
try {
261263
compareAsYaml(clazz, getOpenAPIAsString(file));

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

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.swagger.v3.jaxrs2;
22

3+
import com.fasterxml.jackson.annotation.JsonSubTypes;
34
import com.fasterxml.jackson.databind.ObjectMapper;
45
import io.swagger.v3.core.converter.AnnotatedType;
56
import io.swagger.v3.core.converter.ModelConverter;
@@ -65,8 +66,11 @@
6566
import io.swagger.v3.jaxrs2.resources.extensions.OperationExtensionsResource;
6667
import io.swagger.v3.jaxrs2.resources.extensions.ParameterExtensionsResource;
6768
import io.swagger.v3.jaxrs2.resources.extensions.RequestBodyExtensionsResource;
69+
import io.swagger.v3.jaxrs2.resources.model.Pet;
6870
import io.swagger.v3.jaxrs2.resources.rs.ProcessTokenRestService;
6971
import io.swagger.v3.oas.annotations.enums.ParameterIn;
72+
import io.swagger.v3.oas.annotations.media.Content;
73+
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping;
7074
import io.swagger.v3.oas.models.Components;
7175
import io.swagger.v3.oas.models.ExternalDocumentation;
7276
import io.swagger.v3.oas.models.OpenAPI;
@@ -79,6 +83,7 @@
7983
import io.swagger.v3.oas.models.info.Info;
8084
import io.swagger.v3.oas.models.links.Link;
8185
import io.swagger.v3.oas.models.media.ArraySchema;
86+
import io.swagger.v3.oas.models.media.ComposedSchema;
8287
import io.swagger.v3.oas.models.media.IntegerSchema;
8388
import io.swagger.v3.oas.models.media.Schema;
8489
import io.swagger.v3.oas.models.parameters.Parameter;
@@ -87,17 +92,26 @@
8792
import io.swagger.v3.oas.models.responses.ApiResponses;
8893
import io.swagger.v3.oas.models.security.SecurityRequirement;
8994
import io.swagger.v3.oas.models.security.SecurityScheme;
95+
96+
import org.testng.annotations.BeforeMethod;
9097
import org.testng.annotations.Test;
9198

99+
import javax.validation.constraints.AssertTrue;
92100
import javax.ws.rs.Consumes;
93101
import javax.ws.rs.DELETE;
94102
import javax.ws.rs.GET;
95103
import javax.ws.rs.HEAD;
104+
import javax.ws.rs.NotFoundException;
96105
import javax.ws.rs.OPTIONS;
97106
import javax.ws.rs.POST;
98107
import javax.ws.rs.PUT;
99108
import javax.ws.rs.Path;
100109
import javax.ws.rs.Produces;
110+
import javax.ws.rs.QueryParam;
111+
import javax.ws.rs.core.Response;
112+
import javax.xml.bind.annotation.XmlElement;
113+
import javax.xml.bind.annotation.XmlElementWrapper;
114+
101115
import java.lang.annotation.Annotation;
102116
import java.lang.reflect.Method;
103117
import java.lang.reflect.Type;
@@ -155,6 +169,11 @@ public class ReaderTest {
155169
private static final int SCOPE_NUMBER = 2;
156170
private static final int PATHS_NUMBER = 1;
157171

172+
@BeforeMethod
173+
public void beforeTest() {
174+
ModelConverters.getInstance().resetContext();
175+
}
176+
158177
@Test(description = "test a simple resource class")
159178
public void testSimpleReadClass() {
160179
Reader reader = new Reader(new OpenAPI());
@@ -277,6 +296,44 @@ public void testSetOfClasses() {
277296
assertEquals(SECURITY_SCHEMAS, securitySchemes.size());
278297
}
279298

299+
@JsonSubTypes(@JsonSubTypes.Type(value = SubClass.class))
300+
@io.swagger.v3.oas.annotations.media.Schema(discriminatorProperty = "type_", discriminatorMapping = {
301+
@DiscriminatorMapping(value = "SubClass", schema = SubClass.class)})
302+
private class SuperClass {
303+
public int hi;
304+
}
305+
306+
private class SubClass extends SuperClass{
307+
public int whatsup;
308+
}
309+
310+
private class AnotherController {
311+
312+
@Path("getSuperClass")
313+
@io.swagger.v3.oas.annotations.Operation()
314+
public void getSuperClass(SuperClass superClass) {
315+
}
316+
}
317+
318+
private class Controller {
319+
320+
@Path("getSubClass")
321+
@io.swagger.v3.oas.annotations.Operation()
322+
public void getSubClass(SubClass subClass) {
323+
}
324+
}
325+
326+
@Test(description = "Test a Set of classes")
327+
public void testSetOfClassesSubtypeResolvedSeparatelyFirst() {
328+
329+
Set<Class<?>> classes = new HashSet<>();
330+
classes.add(AnotherController.class);
331+
classes.add(Controller.class);
332+
333+
Reader reader = new Reader(new OpenAPI());
334+
OpenAPI openAPI = reader.read(classes);
335+
assertTrue(openAPI.getComponents().getSchemas().get("SubClass") instanceof ComposedSchema);
336+
}
280337
@Test(description = "Deprecated Method")
281338
public void testDeprecatedMethod() {
282339
Reader reader = new Reader(new OpenAPI());
@@ -2058,13 +2115,13 @@ public void testTicket3082() {
20582115
" type: string\n";
20592116
SerializationMatchers.assertEqualsToYaml(openAPI, yaml);
20602117
}
2061-
2118+
20622119
@Test(description = "Filter class return type")
20632120
public void testTicket3074() {
20642121
Reader reader = new Reader(new OpenAPI());
20652122
OpenAPI oasResult = reader.read(RefParameter3074Resource.class);
20662123
SerializationMatchers.assertEqualsToYaml(oasResult, RefParameter3074Resource.EXPECTED_YAML_WITH_WRAPPER);
2067-
2124+
ModelConverters.getInstance().resetContext();
20682125
ModelConverters.getInstance().addClassToSkip("io.swagger.v3.jaxrs2.resources.RefParameter3074Resource$Wrapper");
20692126

20702127
reader = new Reader(new OpenAPI());

modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/annotations/AbstractAnnotationTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
import com.fasterxml.jackson.annotation.JsonInclude;
44
import com.fasterxml.jackson.databind.JsonNode;
5+
6+
import io.swagger.v3.core.converter.ModelConverter;
7+
import io.swagger.v3.core.converter.ModelConverters;
58
import io.swagger.v3.core.util.Yaml;
69
import io.swagger.v3.jaxrs2.Reader;
710
import io.swagger.v3.jaxrs2.matchers.SerializationMatchers;
811
import io.swagger.v3.oas.models.OpenAPI;
912
import org.apache.commons.io.IOUtils;
13+
import org.testng.annotations.BeforeMethod;
1014

1115
import java.io.IOException;
1216
import java.io.InputStream;
@@ -15,6 +19,11 @@
1519
import static org.testng.Assert.fail;
1620

1721
public abstract class AbstractAnnotationTest {
22+
@BeforeMethod
23+
public void beforeTest() {
24+
ModelConverters.getInstance().resetContext();
25+
}
26+
1827
public String readIntoYaml(final Class<?> cls) {
1928
Reader reader = new Reader(new OpenAPI());
2029
OpenAPI openAPI = reader.read(cls);
@@ -42,6 +51,7 @@ public void compareToYamlFile(final Class<?> cls, String source){
4251
}
4352

4453
public void compareAsYaml(final Class<?> cls, final String yaml) throws IOException {
54+
ModelConverters.getInstance().resetContext();
4555
Reader reader = new Reader(new OpenAPI());
4656
OpenAPI openAPI = reader.read(cls);
4757
SerializationMatchers.assertEqualsToYaml(openAPI, yaml);

0 commit comments

Comments
 (0)