Skip to content

Commit d5f752e

Browse files
authored
Merge pull request #2849 from swagger-api/ref-refactor
refactor and fix references handling
2 parents 1d03f0c + af5df80 commit d5f752e

File tree

20 files changed

+1032
-13
lines changed

20 files changed

+1032
-13
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import javax.xml.bind.annotation.XmlRootElement;
2828
import javax.xml.bind.annotation.XmlSchema;
2929

30+
import io.swagger.models.refs.RefFormat;
3031
import org.apache.commons.lang3.StringUtils;
3132
import org.slf4j.Logger;
3233
import org.slf4j.LoggerFactory;
@@ -173,7 +174,11 @@ public Property resolveProperty(JavaType propType,
173174
}
174175
if (innerModel instanceof ModelImpl) {
175176
ModelImpl mi = (ModelImpl) innerModel;
176-
property = new RefProperty(StringUtils.isNotEmpty(mi.getReference()) ? mi.getReference() : mi.getName());
177+
if (StringUtils.isNotEmpty(mi.getReference())) {
178+
property = new RefProperty(mi.getReference());
179+
} else {
180+
property = new RefProperty(mi.getName(), RefFormat.INTERNAL);
181+
}
177182
}
178183
}
179184
}
@@ -970,7 +975,7 @@ private boolean resolveSubtypes(ModelImpl model, BeanDescription bean, ModelConv
970975
}
971976

972977
impl.setDiscriminator(null);
973-
ComposedModel child = new ComposedModel().parent(new RefModel(model.getName())).child(impl);
978+
ComposedModel child = new ComposedModel().parent(new RefModel(model.getName(), RefFormat.INTERNAL)).child(impl);
974979
context.defineModel(impl.getName(), child, subtypeType, null);
975980
++count;
976981
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.swagger.jackson.mixin;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
5+
public abstract class IgnoreOriginalRefMixin {
6+
7+
@JsonIgnore
8+
public abstract String getOriginalRef();
9+
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.swagger.jackson.mixin;
2+
3+
import com.fasterxml.jackson.annotation.JsonGetter;
4+
import com.fasterxml.jackson.annotation.JsonIgnore;
5+
6+
public abstract class OriginalRefMixin {
7+
8+
@JsonIgnore
9+
public abstract String get$ref();
10+
11+
@JsonGetter("$ref")
12+
public abstract String getOriginalRef();
13+
14+
}

modules/swagger-core/src/main/java/io/swagger/util/ObjectMapperFactory.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
import io.swagger.jackson.mixin.ResponseSchemaMixin;
1111
import io.swagger.models.Response;
1212

13-
14-
15-
1613
public class ObjectMapperFactory {
1714

1815
protected static ObjectMapper createJson() {
@@ -43,6 +40,8 @@ private static ObjectMapper create(JsonFactory jsonFactory, boolean includePathD
4340

4441
mapper.addMixIn(Response.class, ResponseSchemaMixin.class);
4542

43+
ReferenceSerializationConfigurer.serializeAsComputedRef(mapper);
44+
4645
return mapper;
4746
}
4847
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.swagger.util;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import io.swagger.jackson.mixin.IgnoreOriginalRefMixin;
5+
import io.swagger.jackson.mixin.OriginalRefMixin;
6+
import io.swagger.models.RefModel;
7+
import io.swagger.models.RefPath;
8+
import io.swagger.models.RefResponse;
9+
import io.swagger.models.parameters.RefParameter;
10+
import io.swagger.models.properties.RefProperty;
11+
12+
/**
13+
* @since 1.5.21
14+
*/
15+
public abstract class ReferenceSerializationConfigurer {
16+
17+
private static void serializeAs(Class<?> cls, ObjectMapper mapper) {
18+
mapper.addMixIn(RefModel.class, cls);
19+
mapper.addMixIn(RefProperty.class, cls);
20+
mapper.addMixIn(RefPath.class, cls);
21+
mapper.addMixIn(RefParameter.class, cls);
22+
mapper.addMixIn(RefResponse.class, cls);
23+
}
24+
25+
public static void serializeAsOriginalRef() {
26+
serializeAs(OriginalRefMixin.class, Json.mapper());
27+
serializeAs(OriginalRefMixin.class, Yaml.mapper());
28+
}
29+
30+
public static void serializeAsComputedRef() {
31+
serializeAs(IgnoreOriginalRefMixin.class, Json.mapper());
32+
serializeAs(IgnoreOriginalRefMixin.class, Yaml.mapper());
33+
}
34+
35+
public static void serializeAsOriginalRef(ObjectMapper mapper) {
36+
serializeAs(OriginalRefMixin.class, mapper);
37+
}
38+
39+
public static void serializeAsComputedRef(ObjectMapper mapper) {
40+
serializeAs(IgnoreOriginalRefMixin.class, mapper);
41+
}
42+
43+
}

modules/swagger-core/src/test/java/io/swagger/matchers/SerializationMatchers.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public static void assertEqualsToJson(Object objectToSerialize, String jsonStr)
2626
apply(objectToSerialize, jsonStr, Json.mapper());
2727
}
2828

29+
public static void assertEqualsToString(Object objectToSerialize, String jsonStr, ObjectMapper mapper) {
30+
apply(objectToSerialize, jsonStr, mapper);
31+
}
32+
2933
private static void apply(Object objectToSerialize, String str, ObjectMapper mapper) {
3034
final ObjectNode lhs = mapper.convertValue(objectToSerialize, ObjectNode.class);
3135
ObjectNode rhs = null;

modules/swagger-jaxrs/src/test/java/io/swagger/ReferenceTest.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package io.swagger;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
34
import io.swagger.converter.ModelConverters;
45
import io.swagger.jaxrs.Reader;
56
import io.swagger.matchers.SerializationMatchers;
67
import io.swagger.models.Pet;
78
import io.swagger.models.Swagger;
89
import io.swagger.models.properties.Property;
910
import io.swagger.models.properties.RefProperty;
11+
import io.swagger.models.refs.GenericRef;
12+
import io.swagger.resources.ResourceWithMoreReferences;
1013
import io.swagger.resources.ResourceWithReferences;
14+
import io.swagger.util.Json;
15+
import io.swagger.util.ReferenceSerializationConfigurer;
1116
import io.swagger.util.ResourceUtils;
1217
import org.testng.annotations.Test;
1318

@@ -32,8 +37,54 @@ public void scanModel() {
3237

3338
@Test(description = "Scan API with operation and response references")
3439
public void scanAPI() throws IOException {
40+
3541
final Swagger swagger = new Reader(new Swagger()).read(ResourceWithReferences.class);
3642
final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithReferences.json");
3743
SerializationMatchers.assertEqualsToJson(swagger, json);
3844
}
45+
46+
@Test(description = "Scan API with references")
47+
public void scanRef() throws IOException {
48+
49+
final Swagger swagger = new Reader(new Swagger()).read(ResourceWithMoreReferences.class);
50+
final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferences.json");
51+
SerializationMatchers.assertEqualsToJson(swagger, json);
52+
}
53+
54+
@Test(description = "Serialize API with references and OriginalRefMixin activated")
55+
public void serializeRefWithOriginalRef() throws Exception {
56+
57+
// workaround for https://github.com/FasterXML/jackson-databind/issues/1998
58+
ObjectMapper mapper = Json.mapper().copy();
59+
ReferenceSerializationConfigurer.serializeAsOriginalRef(mapper);
60+
61+
final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferencesAsOriginalRef.json");
62+
Swagger swagger = Json.mapper().readValue(json, Swagger.class);
63+
SerializationMatchers.assertEqualsToString(swagger, json, mapper);
64+
}
65+
66+
@Test(description = "Serialize API with references and internal ref also with dots activated")
67+
public void serializeRefWithInternalRef() throws Exception {
68+
try {
69+
GenericRef.internalRefWithAnyDot();
70+
final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferencesWithInternalRef.json");
71+
Swagger swagger = Json.mapper().readValue(json, Swagger.class);
72+
SerializationMatchers.assertEqualsToJson(swagger, json);
73+
} finally {
74+
GenericRef.relativeRefWithAnyDot();
75+
}
76+
}
77+
78+
@Test(description = "Scan API with references and OriginalRefMixin activated")
79+
public void scanRefWithOriginalRef() throws IOException {
80+
81+
// workaround for https://github.com/FasterXML/jackson-databind/issues/1998
82+
ObjectMapper mapper = Json.mapper().copy();
83+
ReferenceSerializationConfigurer.serializeAsOriginalRef(mapper);
84+
85+
final Swagger swagger = new Reader(new Swagger()).read(ResourceWithMoreReferences.class);
86+
final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferencesAsOriginalRef.json");
87+
SerializationMatchers.assertEqualsToString(swagger, json, mapper);
88+
}
89+
3990
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.swagger.models;
2+
3+
import io.swagger.annotations.ApiModelProperty;
4+
5+
public class ModelWithReferences {
6+
public String getOne() {
7+
return null;
8+
}
9+
10+
@ApiModelProperty(reference = "http://swagger.io/schemas.json#/Models/AnotherModel")
11+
public String getAnother() {
12+
return null;
13+
}
14+
15+
@ApiModelProperty(reference = "Three")
16+
public String getThree() {
17+
return null;
18+
}
19+
20+
@ApiModelProperty(reference = "Four.json")
21+
public String getFour() {
22+
return null;
23+
}
24+
25+
@ApiModelProperty(reference = "Five.json.MyClass")
26+
public String getFive() {
27+
return null;
28+
}
29+
30+
@ApiModelProperty(reference = "./Six")
31+
public String getSix() {
32+
return null;
33+
}
34+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package io.swagger.resources;
2+
3+
import io.swagger.annotations.Api;
4+
import io.swagger.annotations.ApiOperation;
5+
import io.swagger.annotations.ApiResponse;
6+
import io.swagger.annotations.ApiResponses;
7+
import io.swagger.models.ModelContainingModelWithReference;
8+
import io.swagger.models.ModelWithReference;
9+
import io.swagger.models.ModelWithReferences;
10+
11+
import javax.ws.rs.GET;
12+
import javax.ws.rs.Path;
13+
import javax.ws.rs.WebApplicationException;
14+
import javax.ws.rs.core.Response;
15+
16+
@Api(value = "/basic")
17+
@Path("/")
18+
public class ResourceWithMoreReferences {
19+
20+
@GET
21+
@Path("/test")
22+
@ApiResponses({
23+
@ApiResponse(code = 500, message = "Error", reference = "http://swagger.io/schemas.json#/Models/ErrorResponse")
24+
})
25+
public Response getTest() throws WebApplicationException {
26+
return Response.ok().build();
27+
}
28+
29+
@GET
30+
@Path("/some")
31+
@ApiOperation(value = "Get Some", responseReference = "http://swagger.io/schemas.json#/Models/SomeResponse")
32+
public Response getSome() throws WebApplicationException {
33+
return Response.ok().build();
34+
}
35+
36+
@GET
37+
@Path("/testSome")
38+
@ApiOperation(value = "Get Some", responseReference = "http://swagger.io/schemas.json#/Models/SomeResponse")
39+
@ApiResponses({
40+
@ApiResponse(code = 500, message = "Error", reference = "http://swagger.io/schemas.json#/Models/ErrorResponse")
41+
})
42+
public Response getTestSome() throws WebApplicationException {
43+
return Response.ok().build();
44+
}
45+
46+
@GET
47+
@Path("/testSomeOther")
48+
@ApiOperation(value = "Get Some Other", responseReference = "foo")
49+
@ApiResponses({
50+
@ApiResponse(code = 500, message = "Error", reference = "foo.json"),
51+
@ApiResponse(code = 502, message = "Error", reference = "foo.json.MyClass")
52+
})
53+
public Response getTestSomeOther() throws WebApplicationException {
54+
return Response.ok().build();
55+
}
56+
57+
@GET
58+
@Path("/model")
59+
@ApiOperation(value = "Get Model", response = ModelContainingModelWithReference.class)
60+
public Response getModel() throws WebApplicationException {
61+
return Response.ok().build();
62+
}
63+
64+
@GET
65+
@Path("/anotherModel")
66+
@ApiOperation(value = "Get Another Model", response = ModelWithReference.class)
67+
public Response getAnotherModel() throws WebApplicationException {
68+
return Response.ok().build();
69+
}
70+
71+
@GET
72+
@Path("/aThirdModel")
73+
@ApiOperation(value = "Get A Third Model", response = ModelWithReferences.class)
74+
public Response getAThirdModel() throws WebApplicationException {
75+
return Response.ok().build();
76+
}
77+
}

0 commit comments

Comments
 (0)