diff --git a/modules/swagger-core/src/main/java/io/swagger/jackson/ModelResolver.java b/modules/swagger-core/src/main/java/io/swagger/jackson/ModelResolver.java index 5d4269ad75..8aea946aa9 100644 --- a/modules/swagger-core/src/main/java/io/swagger/jackson/ModelResolver.java +++ b/modules/swagger-core/src/main/java/io/swagger/jackson/ModelResolver.java @@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSchema; +import io.swagger.models.refs.RefFormat; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -173,7 +174,11 @@ public Property resolveProperty(JavaType propType, } if (innerModel instanceof ModelImpl) { ModelImpl mi = (ModelImpl) innerModel; - property = new RefProperty(StringUtils.isNotEmpty(mi.getReference()) ? mi.getReference() : mi.getName()); + if (StringUtils.isNotEmpty(mi.getReference())) { + property = new RefProperty(mi.getReference()); + } else { + property = new RefProperty(mi.getName(), RefFormat.INTERNAL); + } } } } @@ -970,7 +975,7 @@ private boolean resolveSubtypes(ModelImpl model, BeanDescription bean, ModelConv } impl.setDiscriminator(null); - ComposedModel child = new ComposedModel().parent(new RefModel(model.getName())).child(impl); + ComposedModel child = new ComposedModel().parent(new RefModel(model.getName(), RefFormat.INTERNAL)).child(impl); context.defineModel(impl.getName(), child, subtypeType, null); ++count; } diff --git a/modules/swagger-core/src/main/java/io/swagger/jackson/mixin/IgnoreOriginalRefMixin.java b/modules/swagger-core/src/main/java/io/swagger/jackson/mixin/IgnoreOriginalRefMixin.java new file mode 100644 index 0000000000..880167a39a --- /dev/null +++ b/modules/swagger-core/src/main/java/io/swagger/jackson/mixin/IgnoreOriginalRefMixin.java @@ -0,0 +1,10 @@ +package io.swagger.jackson.mixin; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public abstract class IgnoreOriginalRefMixin { + + @JsonIgnore + public abstract String getOriginalRef(); + +} diff --git a/modules/swagger-core/src/main/java/io/swagger/jackson/mixin/OriginalRefMixin.java b/modules/swagger-core/src/main/java/io/swagger/jackson/mixin/OriginalRefMixin.java new file mode 100644 index 0000000000..589d1155cc --- /dev/null +++ b/modules/swagger-core/src/main/java/io/swagger/jackson/mixin/OriginalRefMixin.java @@ -0,0 +1,14 @@ +package io.swagger.jackson.mixin; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; + +public abstract class OriginalRefMixin { + + @JsonIgnore + public abstract String get$ref(); + + @JsonGetter("$ref") + public abstract String getOriginalRef(); + +} diff --git a/modules/swagger-core/src/main/java/io/swagger/util/ObjectMapperFactory.java b/modules/swagger-core/src/main/java/io/swagger/util/ObjectMapperFactory.java index 1cc301ee04..6a5f2e83ea 100644 --- a/modules/swagger-core/src/main/java/io/swagger/util/ObjectMapperFactory.java +++ b/modules/swagger-core/src/main/java/io/swagger/util/ObjectMapperFactory.java @@ -10,9 +10,6 @@ import io.swagger.jackson.mixin.ResponseSchemaMixin; import io.swagger.models.Response; - - - public class ObjectMapperFactory { protected static ObjectMapper createJson() { @@ -43,6 +40,8 @@ private static ObjectMapper create(JsonFactory jsonFactory, boolean includePathD mapper.addMixIn(Response.class, ResponseSchemaMixin.class); + ReferenceSerializationConfigurer.serializeAsComputedRef(mapper); + return mapper; } } diff --git a/modules/swagger-core/src/main/java/io/swagger/util/ReferenceSerializationConfigurer.java b/modules/swagger-core/src/main/java/io/swagger/util/ReferenceSerializationConfigurer.java new file mode 100644 index 0000000000..87c8921a01 --- /dev/null +++ b/modules/swagger-core/src/main/java/io/swagger/util/ReferenceSerializationConfigurer.java @@ -0,0 +1,43 @@ +package io.swagger.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.jackson.mixin.IgnoreOriginalRefMixin; +import io.swagger.jackson.mixin.OriginalRefMixin; +import io.swagger.models.RefModel; +import io.swagger.models.RefPath; +import io.swagger.models.RefResponse; +import io.swagger.models.parameters.RefParameter; +import io.swagger.models.properties.RefProperty; + +/** + * @since 1.5.21 + */ +public abstract class ReferenceSerializationConfigurer { + + private static void serializeAs(Class cls, ObjectMapper mapper) { + mapper.addMixIn(RefModel.class, cls); + mapper.addMixIn(RefProperty.class, cls); + mapper.addMixIn(RefPath.class, cls); + mapper.addMixIn(RefParameter.class, cls); + mapper.addMixIn(RefResponse.class, cls); + } + + public static void serializeAsOriginalRef() { + serializeAs(OriginalRefMixin.class, Json.mapper()); + serializeAs(OriginalRefMixin.class, Yaml.mapper()); + } + + public static void serializeAsComputedRef() { + serializeAs(IgnoreOriginalRefMixin.class, Json.mapper()); + serializeAs(IgnoreOriginalRefMixin.class, Yaml.mapper()); + } + + public static void serializeAsOriginalRef(ObjectMapper mapper) { + serializeAs(OriginalRefMixin.class, mapper); + } + + public static void serializeAsComputedRef(ObjectMapper mapper) { + serializeAs(IgnoreOriginalRefMixin.class, mapper); + } + +} diff --git a/modules/swagger-core/src/test/java/io/swagger/matchers/SerializationMatchers.java b/modules/swagger-core/src/test/java/io/swagger/matchers/SerializationMatchers.java index b2af77fbc6..9748e69410 100644 --- a/modules/swagger-core/src/test/java/io/swagger/matchers/SerializationMatchers.java +++ b/modules/swagger-core/src/test/java/io/swagger/matchers/SerializationMatchers.java @@ -26,6 +26,10 @@ public static void assertEqualsToJson(Object objectToSerialize, String jsonStr) apply(objectToSerialize, jsonStr, Json.mapper()); } + public static void assertEqualsToString(Object objectToSerialize, String jsonStr, ObjectMapper mapper) { + apply(objectToSerialize, jsonStr, mapper); + } + private static void apply(Object objectToSerialize, String str, ObjectMapper mapper) { final ObjectNode lhs = mapper.convertValue(objectToSerialize, ObjectNode.class); ObjectNode rhs = null; diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/ReferenceTest.java b/modules/swagger-jaxrs/src/test/java/io/swagger/ReferenceTest.java index 81506196a8..b7e85b8875 100644 --- a/modules/swagger-jaxrs/src/test/java/io/swagger/ReferenceTest.java +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/ReferenceTest.java @@ -1,5 +1,6 @@ package io.swagger; +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.converter.ModelConverters; import io.swagger.jaxrs.Reader; import io.swagger.matchers.SerializationMatchers; @@ -7,7 +8,11 @@ import io.swagger.models.Swagger; import io.swagger.models.properties.Property; import io.swagger.models.properties.RefProperty; +import io.swagger.models.refs.GenericRef; +import io.swagger.resources.ResourceWithMoreReferences; import io.swagger.resources.ResourceWithReferences; +import io.swagger.util.Json; +import io.swagger.util.ReferenceSerializationConfigurer; import io.swagger.util.ResourceUtils; import org.testng.annotations.Test; @@ -32,8 +37,54 @@ public void scanModel() { @Test(description = "Scan API with operation and response references") public void scanAPI() throws IOException { + final Swagger swagger = new Reader(new Swagger()).read(ResourceWithReferences.class); final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithReferences.json"); SerializationMatchers.assertEqualsToJson(swagger, json); } + + @Test(description = "Scan API with references") + public void scanRef() throws IOException { + + final Swagger swagger = new Reader(new Swagger()).read(ResourceWithMoreReferences.class); + final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferences.json"); + SerializationMatchers.assertEqualsToJson(swagger, json); + } + + @Test(description = "Serialize API with references and OriginalRefMixin activated") + public void serializeRefWithOriginalRef() throws Exception { + + // workaround for https://github.com/FasterXML/jackson-databind/issues/1998 + ObjectMapper mapper = Json.mapper().copy(); + ReferenceSerializationConfigurer.serializeAsOriginalRef(mapper); + + final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferencesAsOriginalRef.json"); + Swagger swagger = Json.mapper().readValue(json, Swagger.class); + SerializationMatchers.assertEqualsToString(swagger, json, mapper); + } + + @Test(description = "Serialize API with references and internal ref also with dots activated") + public void serializeRefWithInternalRef() throws Exception { + try { + GenericRef.internalRefWithAnyDot(); + final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferencesWithInternalRef.json"); + Swagger swagger = Json.mapper().readValue(json, Swagger.class); + SerializationMatchers.assertEqualsToJson(swagger, json); + } finally { + GenericRef.relativeRefWithAnyDot(); + } + } + + @Test(description = "Scan API with references and OriginalRefMixin activated") + public void scanRefWithOriginalRef() throws IOException { + + // workaround for https://github.com/FasterXML/jackson-databind/issues/1998 + ObjectMapper mapper = Json.mapper().copy(); + ReferenceSerializationConfigurer.serializeAsOriginalRef(mapper); + + final Swagger swagger = new Reader(new Swagger()).read(ResourceWithMoreReferences.class); + final String json = ResourceUtils.loadClassResource(getClass(), "ResourceWithMoreReferencesAsOriginalRef.json"); + SerializationMatchers.assertEqualsToString(swagger, json, mapper); + } + } diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/models/ModelWithReferences.java b/modules/swagger-jaxrs/src/test/java/io/swagger/models/ModelWithReferences.java new file mode 100644 index 0000000000..45b6243698 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/models/ModelWithReferences.java @@ -0,0 +1,34 @@ +package io.swagger.models; + +import io.swagger.annotations.ApiModelProperty; + +public class ModelWithReferences { + public String getOne() { + return null; + } + + @ApiModelProperty(reference = "http://swagger.io/schemas.json#/Models/AnotherModel") + public String getAnother() { + return null; + } + + @ApiModelProperty(reference = "Three") + public String getThree() { + return null; + } + + @ApiModelProperty(reference = "Four.json") + public String getFour() { + return null; + } + + @ApiModelProperty(reference = "Five.json.MyClass") + public String getFive() { + return null; + } + + @ApiModelProperty(reference = "./Six") + public String getSix() { + return null; + } +} diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/resources/ResourceWithMoreReferences.java b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/ResourceWithMoreReferences.java new file mode 100644 index 0000000000..98acc5f8e5 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/ResourceWithMoreReferences.java @@ -0,0 +1,77 @@ +package io.swagger.resources; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.models.ModelContainingModelWithReference; +import io.swagger.models.ModelWithReference; +import io.swagger.models.ModelWithReferences; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; + +@Api(value = "/basic") +@Path("/") +public class ResourceWithMoreReferences { + + @GET + @Path("/test") + @ApiResponses({ + @ApiResponse(code = 500, message = "Error", reference = "http://swagger.io/schemas.json#/Models/ErrorResponse") + }) + public Response getTest() throws WebApplicationException { + return Response.ok().build(); + } + + @GET + @Path("/some") + @ApiOperation(value = "Get Some", responseReference = "http://swagger.io/schemas.json#/Models/SomeResponse") + public Response getSome() throws WebApplicationException { + return Response.ok().build(); + } + + @GET + @Path("/testSome") + @ApiOperation(value = "Get Some", responseReference = "http://swagger.io/schemas.json#/Models/SomeResponse") + @ApiResponses({ + @ApiResponse(code = 500, message = "Error", reference = "http://swagger.io/schemas.json#/Models/ErrorResponse") + }) + public Response getTestSome() throws WebApplicationException { + return Response.ok().build(); + } + + @GET + @Path("/testSomeOther") + @ApiOperation(value = "Get Some Other", responseReference = "foo") + @ApiResponses({ + @ApiResponse(code = 500, message = "Error", reference = "foo.json"), + @ApiResponse(code = 502, message = "Error", reference = "foo.json.MyClass") + }) + public Response getTestSomeOther() throws WebApplicationException { + return Response.ok().build(); + } + + @GET + @Path("/model") + @ApiOperation(value = "Get Model", response = ModelContainingModelWithReference.class) + public Response getModel() throws WebApplicationException { + return Response.ok().build(); + } + + @GET + @Path("/anotherModel") + @ApiOperation(value = "Get Another Model", response = ModelWithReference.class) + public Response getAnotherModel() throws WebApplicationException { + return Response.ok().build(); + } + + @GET + @Path("/aThirdModel") + @ApiOperation(value = "Get A Third Model", response = ModelWithReferences.class) + public Response getAThirdModel() throws WebApplicationException { + return Response.ok().build(); + } +} diff --git a/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferences.json b/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferences.json new file mode 100644 index 0000000000..f5a75a2c87 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferences.json @@ -0,0 +1,222 @@ +{ + "swagger": "2.0", + "tags": [ + { + "name": "basic" + } + ], + "paths": { + "/test": { + "get": { + "tags": [ + "basic" + ], + "operationId": "getTest", + "parameters": [], + "responses": { + "500": { + "description": "Error", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/ErrorResponse" + } + } + } + } + }, + "/some": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some", + "description": "", + "operationId": "getSome", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/SomeResponse" + } + } + } + } + }, + "/testSome": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some", + "description": "", + "operationId": "getTestSome", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/SomeResponse" + } + }, + "500": { + "description": "Error", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/ErrorResponse" + } + } + } + } + }, + "/testSomeOther": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some Other", + "description": "", + "operationId": "getTestSomeOther", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/foo" + } + }, + "500": { + "description": "Error", + "schema": { + "$ref": "foo.json" + } + }, + "502": { + "description": "Error", + "schema": { + "$ref": "foo.json.MyClass" + } + } + } + } + }, + "/model": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Model", + "description": "", + "operationId": "getModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/ModelContainingModelWithReference" + } + } + } + } + }, + "/anotherModel": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Another Model", + "description": "", + "operationId": "getAnotherModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models" + } + } + } + } + }, + "/aThirdModel": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get A Third Model", + "description": "", + "operationId": "getAThirdModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/ModelWithReferences" + } + } + } + } + } + }, + "definitions": { + "ModelContainingModelWithReference": { + "type": "object", + "properties": { + "model": { + "$ref": "http://swagger.io/schemas.json#/Models" + }, + "anotherModel": { + "$ref": "http://swagger.io/schemas.json#/Models/AnotherModel" + } + } + }, + "ModelWithReference": { + "type": "object", + "properties": { + "nested": { + "type": "array", + "description": "SubModelWithSelfReference", + "items": { + "$ref": "#/definitions/SubModelWithSelfReference" + } + }, + "description": { + "$ref": "http://swagger.io/schemas.json#/Models/Description" + } + } + }, + "SubModelWithSelfReference": { + "type": "object", + "properties": { + "references": { + "type": "array", + "description": "References", + "items": { + "$ref": "#/definitions/SubModelWithSelfReference" + } + } + } + }, + "ModelWithReferences": { + "type": "object", + "properties": { + "one": { + "type": "string" + }, + "five": { + "$ref": "Five.json.MyClass" + }, + "four": { + "$ref": "Four.json" + }, + "six": { + "$ref": "./Six" + }, + "three": { + "$ref": "#/definitions/Three" + }, + "another": { + "$ref": "http://swagger.io/schemas.json#/Models/AnotherModel" + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferencesAsOriginalRef.json b/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferencesAsOriginalRef.json new file mode 100644 index 0000000000..9665f2d077 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferencesAsOriginalRef.json @@ -0,0 +1,222 @@ +{ + "swagger": "2.0", + "tags": [ + { + "name": "basic" + } + ], + "paths": { + "/test": { + "get": { + "tags": [ + "basic" + ], + "operationId": "getTest", + "parameters": [], + "responses": { + "500": { + "description": "Error", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/ErrorResponse" + } + } + } + } + }, + "/some": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some", + "description": "", + "operationId": "getSome", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/SomeResponse" + } + } + } + } + }, + "/testSome": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some", + "description": "", + "operationId": "getTestSome", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/SomeResponse" + } + }, + "500": { + "description": "Error", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/ErrorResponse" + } + } + } + } + }, + "/testSomeOther": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some Other", + "description": "", + "operationId": "getTestSomeOther", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "foo" + } + }, + "500": { + "description": "Error", + "schema": { + "$ref": "foo.json" + } + }, + "502": { + "description": "Error", + "schema": { + "$ref": "foo.json.MyClass" + } + } + } + } + }, + "/model": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Model", + "description": "", + "operationId": "getModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "ModelContainingModelWithReference" + } + } + } + } + }, + "/anotherModel": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Another Model", + "description": "", + "operationId": "getAnotherModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models" + } + } + } + } + }, + "/aThirdModel": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get A Third Model", + "description": "", + "operationId": "getAThirdModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "ModelWithReferences" + } + } + } + } + } + }, + "definitions": { + "ModelContainingModelWithReference": { + "type": "object", + "properties": { + "model": { + "$ref": "http://swagger.io/schemas.json#/Models" + }, + "anotherModel": { + "$ref": "http://swagger.io/schemas.json#/Models/AnotherModel" + } + } + }, + "ModelWithReference": { + "type": "object", + "properties": { + "nested": { + "type": "array", + "description": "SubModelWithSelfReference", + "items": { + "$ref": "SubModelWithSelfReference" + } + }, + "description": { + "$ref": "http://swagger.io/schemas.json#/Models/Description" + } + } + }, + "SubModelWithSelfReference": { + "type": "object", + "properties": { + "references": { + "type": "array", + "description": "References", + "items": { + "$ref": "SubModelWithSelfReference" + } + } + } + }, + "ModelWithReferences": { + "type": "object", + "properties": { + "six": { + "$ref": "./Six" + }, + "four": { + "$ref": "Four.json" + }, + "another": { + "$ref": "http://swagger.io/schemas.json#/Models/AnotherModel" + }, + "three": { + "$ref": "Three" + }, + "five": { + "$ref": "Five.json.MyClass" + }, + "one": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferencesWithInternalRef.json b/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferencesWithInternalRef.json new file mode 100644 index 0000000000..8abd2c8e4e --- /dev/null +++ b/modules/swagger-jaxrs/src/test/resources/ResourceWithMoreReferencesWithInternalRef.json @@ -0,0 +1,222 @@ +{ + "swagger": "2.0", + "tags": [ + { + "name": "basic" + } + ], + "paths": { + "/test": { + "get": { + "tags": [ + "basic" + ], + "operationId": "getTest", + "parameters": [], + "responses": { + "500": { + "description": "Error", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/ErrorResponse" + } + } + } + } + }, + "/some": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some", + "description": "", + "operationId": "getSome", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/SomeResponse" + } + } + } + } + }, + "/testSome": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some", + "description": "", + "operationId": "getTestSome", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/SomeResponse" + } + }, + "500": { + "description": "Error", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models/ErrorResponse" + } + } + } + } + }, + "/testSomeOther": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Some Other", + "description": "", + "operationId": "getTestSomeOther", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/foo" + } + }, + "500": { + "description": "Error", + "schema": { + "$ref": "#/definitions/foo.json" + } + }, + "502": { + "description": "Error", + "schema": { + "$ref": "#/definitions/foo.json.MyClass" + } + } + } + } + }, + "/model": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Model", + "description": "", + "operationId": "getModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/ModelContainingModelWithReference" + } + } + } + } + }, + "/anotherModel": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get Another Model", + "description": "", + "operationId": "getAnotherModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "http://swagger.io/schemas.json#/Models" + } + } + } + } + }, + "/aThirdModel": { + "get": { + "tags": [ + "basic" + ], + "summary": "Get A Third Model", + "description": "", + "operationId": "getAThirdModel", + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/ModelWithReferences" + } + } + } + } + } + }, + "definitions": { + "ModelContainingModelWithReference": { + "type": "object", + "properties": { + "model": { + "$ref": "http://swagger.io/schemas.json#/Models" + }, + "anotherModel": { + "$ref": "http://swagger.io/schemas.json#/Models/AnotherModel" + } + } + }, + "ModelWithReference": { + "type": "object", + "properties": { + "nested": { + "type": "array", + "description": "SubModelWithSelfReference", + "items": { + "$ref": "#/definitions/SubModelWithSelfReference" + } + }, + "description": { + "$ref": "http://swagger.io/schemas.json#/Models/Description" + } + } + }, + "SubModelWithSelfReference": { + "type": "object", + "properties": { + "references": { + "type": "array", + "description": "References", + "items": { + "$ref": "#/definitions/SubModelWithSelfReference" + } + } + } + }, + "ModelWithReferences": { + "type": "object", + "properties": { + "six": { + "$ref": "./Six" + }, + "four": { + "$ref": "#/definitions/Four.json" + }, + "another": { + "$ref": "http://swagger.io/schemas.json#/Models/AnotherModel" + }, + "three": { + "$ref": "#/definitions/Three" + }, + "five": { + "$ref": "#/definitions/Five.json.MyClass" + }, + "one": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-models/src/main/java/io/swagger/models/RefModel.java b/modules/swagger-models/src/main/java/io/swagger/models/RefModel.java index 7afb19fb25..a56d995d19 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/RefModel.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/RefModel.java @@ -23,6 +23,10 @@ public RefModel(String ref) { set$ref(ref); } + public RefModel(String ref, RefFormat refFormat) { + this.genericRef = new GenericRef(RefType.DEFINITION, ref, refFormat); + } + public RefModel asDefault(String ref) { this.set$ref(RefType.DEFINITION.getInternalPrefix() + ref); return this; @@ -64,6 +68,18 @@ public String getSimpleRef() { return genericRef.getSimpleRef(); } + /** + * @since 1.5.21 + * @return originalRef + */ + public String getOriginalRef() { + if (genericRef != null) { + return genericRef.getOriginalRef(); + } else { + return null; + } + } + public String get$ref() { return genericRef.getRef(); } diff --git a/modules/swagger-models/src/main/java/io/swagger/models/RefPath.java b/modules/swagger-models/src/main/java/io/swagger/models/RefPath.java index 252599c250..8c9d5eed5a 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/RefPath.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/RefPath.java @@ -27,6 +27,10 @@ public RefPath(String ref) { set$ref(ref); } + public RefPath(String ref, RefFormat refFormat) { + this.genericRef = new GenericRef(RefType.PATH, ref, refFormat); + } + public void set$ref(String ref) { this.genericRef = new GenericRef(RefType.PATH, ref); } @@ -35,6 +39,18 @@ public RefPath(String ref) { return genericRef.getRef(); } + /** + * @since 1.5.21 + * @return originalRef + */ + public String getOriginalRef() { + if (genericRef != null) { + return genericRef.getOriginalRef(); + } else { + return null; + } + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/modules/swagger-models/src/main/java/io/swagger/models/RefResponse.java b/modules/swagger-models/src/main/java/io/swagger/models/RefResponse.java index 082ce7dbd9..aa7de65320 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/RefResponse.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/RefResponse.java @@ -36,6 +36,18 @@ public String getSimpleRef() { return genericRef.getSimpleRef(); } + /** + * @since 1.5.21 + * @return originalRef + */ + public String getOriginalRef() { + if (genericRef != null) { + return genericRef.getOriginalRef(); + } else { + return null; + } + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/modules/swagger-models/src/main/java/io/swagger/models/parameters/RefParameter.java b/modules/swagger-models/src/main/java/io/swagger/models/parameters/RefParameter.java index 5df2ec9924..b229880dc6 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/parameters/RefParameter.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/parameters/RefParameter.java @@ -12,6 +12,10 @@ public RefParameter(String ref) { set$ref(ref); } + public RefParameter(String ref, RefFormat refFormat) { + this.genericRef = new GenericRef(RefType.PARAMETER, ref, refFormat); + } + public static boolean isType(String type, String format) { if ("$ref".equals(type)) { return true; @@ -54,6 +58,18 @@ public String getSimpleRef() { return genericRef.getSimpleRef(); } + /** + * @since 1.5.21 + * @return originalRef + */ + public String getOriginalRef() { + if (genericRef != null) { + return genericRef.getOriginalRef(); + } else { + return null; + } + } + @Override public int hashCode() { final int prime = 31; diff --git a/modules/swagger-models/src/main/java/io/swagger/models/properties/PropertyBuilder.java b/modules/swagger-models/src/main/java/io/swagger/models/properties/PropertyBuilder.java index 24fb5c7338..9e3ffb6c28 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/properties/PropertyBuilder.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/properties/PropertyBuilder.java @@ -464,7 +464,7 @@ protected RefProperty create() { public Model toModel(Property property) { if (property instanceof RefProperty) { final RefProperty resolved = (RefProperty) property; - final RefModel model = new RefModel(resolved.get$ref()); + final RefModel model = new RefModel(resolved.getOriginalRef(), resolved.getRefFormat()); model.setDescription(resolved.getDescription()); return model; } diff --git a/modules/swagger-models/src/main/java/io/swagger/models/properties/RefProperty.java b/modules/swagger-models/src/main/java/io/swagger/models/properties/RefProperty.java index 6d0568222c..ee1638051e 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/properties/RefProperty.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/properties/RefProperty.java @@ -16,8 +16,12 @@ public RefProperty() { } public RefProperty(String ref) { + this(ref, null); + } + + public RefProperty(String ref, RefFormat refFormat) { this(); - set$ref(ref); + this.genericRef = new GenericRef(RefType.DEFINITION, ref, refFormat); } public static boolean isType(String type, String format) { @@ -76,6 +80,18 @@ public String getSimpleRef() { } } + /** + * @since 1.5.21 + * @return originalRef + */ + public String getOriginalRef() { + if (genericRef != null) { + return genericRef.getOriginalRef(); + } else { + return null; + } + } + @Override public int hashCode() { final int prime = 31; diff --git a/modules/swagger-models/src/main/java/io/swagger/models/refs/GenericRef.java b/modules/swagger-models/src/main/java/io/swagger/models/refs/GenericRef.java index 333cb54456..600fdfb07a 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/refs/GenericRef.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/refs/GenericRef.java @@ -7,15 +7,41 @@ public class GenericRef { private RefFormat format; private RefType type; private String ref; + private String originalRef; private String simpleRef; + private static boolean relativeRefWithAnyDot = true; + + public static void relativeRefWithAnyDot() { + relativeRefWithAnyDot = true; + } + + public static void internalRefWithAnyDot() { + relativeRefWithAnyDot = false; + } + + public static boolean isRelativeRefWithAnyDot() { + return relativeRefWithAnyDot; + } + + public GenericRef(){} public GenericRef(RefType type, String ref) { - this.format = computeRefFormat(ref); + this(type, ref, null); + } + + public GenericRef(RefType type, String ref, RefFormat format) { + this.originalRef = ref; + if (format == null) { + this.format = computeRefFormat(ref); + } else { + this.format = format; + } + this.type = type; - if (format == RefFormat.INTERNAL && !ref.startsWith("#/")) { + if (this.format == RefFormat.INTERNAL && !ref.startsWith("#/")) { /* this is an internal path that did not start with a #/, we must be in some of ModelResolver code while currently relies on the ability to create RefModel/RefProperty objects via a constructor call like 1) new RefModel("Animal")..and expects get$ref to return #/definitions/Animal @@ -26,7 +52,7 @@ public GenericRef(RefType type, String ref) { this.ref = ref; } - this.simpleRef = computeSimpleRef(this.ref, format, type); + this.simpleRef = computeSimpleRef(this.ref, this.format, type); } public RefFormat getFormat() { @@ -45,6 +71,10 @@ public String getSimpleRef() { return simpleRef; } + public String getOriginalRef() { + return originalRef; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -65,6 +95,9 @@ public boolean equals(Object o) { if (ref != null ? !ref.equals(that.ref) : that.ref != null) { return false; } + if (originalRef != null ? !originalRef.equals(that.originalRef) : that.originalRef != null) { + return false; + } return simpleRef != null ? simpleRef.equals(that.simpleRef) : that.simpleRef == null; } @@ -74,6 +107,7 @@ public int hashCode() { int result = format != null ? format.hashCode() : 0; result = 31 * result + (type != null ? type.hashCode() : 0); result = 31 * result + (ref != null ? ref.hashCode() : 0); + result = 31 * result + (originalRef != null ? originalRef.hashCode() : 0); result = 31 * result + (simpleRef != null ? simpleRef.hashCode() : 0); return result; } @@ -97,8 +131,14 @@ private static RefFormat computeRefFormat(String ref) { result = RefFormat.INTERNAL; } else if (ref.startsWith(".") || ref.startsWith("/")) { result = RefFormat.RELATIVE; + } else if ( + relativeRefWithAnyDot && + !ref.contains(":") && // No scheme + !ref.startsWith("#") && // Path is not empty + !ref.startsWith("/")&& // Path is not absolute + ref.indexOf(".") > -1) { + result = RefFormat.RELATIVE; } - return result; } diff --git a/modules/swagger-models/src/main/java/io/swagger/models/utils/PropertyModelConverter.java b/modules/swagger-models/src/main/java/io/swagger/models/utils/PropertyModelConverter.java index 387793353d..d4729eb42a 100644 --- a/modules/swagger-models/src/main/java/io/swagger/models/utils/PropertyModelConverter.java +++ b/modules/swagger-models/src/main/java/io/swagger/models/utils/PropertyModelConverter.java @@ -92,7 +92,7 @@ public Property modelToProperty(Model model){ } else if(model instanceof RefModel) { RefModel ref = (RefModel) model; - RefProperty refProperty = new RefProperty(ref.get$ref()); + RefProperty refProperty = new RefProperty(ref.get$ref(), ref.getRefFormat()); return refProperty; } else if(model instanceof ComposedModel) { @@ -182,7 +182,7 @@ public Model propertyToModel(Property property){ if(property instanceof RefProperty){ RefProperty ref = (RefProperty) property; - RefModel refModel = new RefModel(ref.get$ref()); + RefModel refModel = new RefModel(ref.getOriginalRef(), ref.getRefFormat()); return refModel; }