From ccf2e3984c4db3762fb3f8cbb5528b318afe30a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ma=C5=82ek?= Date: Wed, 13 Mar 2019 07:39:00 +0100 Subject: [PATCH] #1040 Fixed duplication of external reference path --- .../processors/ExternalRefProcessor.java | 8 +- .../io/swagger/v3/parser/util/RefUtils.java | 38 +++++++-- .../v3/parser/test/OpenAPIV3ParserTest.java | 21 +++++ .../swagger/v3/parser/util/RefUtilsTest.java | 83 ++++++++++++++++++- .../src/test/resources/issue-1040/api.yaml | 16 ++++ .../test/resources/issue-1040/lib/lib.yaml | 13 +++ 6 files changed, 169 insertions(+), 10 deletions(-) create mode 100644 modules/swagger-parser-v3/src/test/resources/issue-1040/api.yaml create mode 100644 modules/swagger-parser-v3/src/test/resources/issue-1040/lib/lib.yaml diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java index 685242c63d..92be9d0a5b 100644 --- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java +++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java @@ -20,6 +20,8 @@ import io.swagger.v3.parser.ResolverCache; import io.swagger.v3.parser.models.RefFormat; import io.swagger.v3.parser.models.RefType; +import io.swagger.v3.parser.util.RefUtils; + import org.apache.commons.lang3.StringUtils; import org.slf4j.LoggerFactory; @@ -27,9 +29,11 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import static io.swagger.v3.parser.util.RefUtils.computeDefinitionName; import static io.swagger.v3.parser.util.RefUtils.computeRefFormat; +import static io.swagger.v3.parser.util.RefUtils.getExternalPath; import static io.swagger.v3.parser.util.RefUtils.isAnExternalRefFormat; public final class ExternalRefProcessor { @@ -689,8 +693,10 @@ private void processRefSchema(Schema subRef, String externalFile) { return; } String $ref = subRef.get$ref(); + String subRefExternalPath = getExternalPath(subRef.get$ref()) + .orElse(null); - if (format.equals(RefFormat.RELATIVE)) { + if (format.equals(RefFormat.RELATIVE) && !Objects.equals(subRefExternalPath, externalFile)) { $ref = constructRef(subRef, externalFile); subRef.set$ref($ref); }else { diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/RefUtils.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/RefUtils.java index 9c0d8c317d..328e2aa05a 100644 --- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/RefUtils.java +++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/RefUtils.java @@ -5,19 +5,27 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; - +import static java.nio.charset.StandardCharsets.UTF_8; import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import java.util.Set; +import java.util.Optional; public class RefUtils { + private static final String REFERENCE_SEPARATOR = "#/"; + + private RefUtils() { + // static access only + } + public static String computeDefinitionName(String ref) { - final String[] refParts = ref.split("#/"); + final String[] refParts = ref.split(REFERENCE_SEPARATOR); if (refParts.length > 2) { throw new RuntimeException("Invalid ref format: " + ref); @@ -43,6 +51,16 @@ public static String computeDefinitionName(String ref) { return plausibleName; } + public static Optional getExternalPath(String ref) { + if (ref == null) { + return Optional.empty(); + } + return Optional.of(ref.split(REFERENCE_SEPARATOR)) + .filter(it -> it.length == 2) + .map(it -> it[0]) + .filter(it -> !it.isEmpty()); + } + public static boolean isAnExternalRefFormat(RefFormat refFormat) { return refFormat == RefFormat.URL || refFormat == RefFormat.RELATIVE; } @@ -52,9 +70,9 @@ public static RefFormat computeRefFormat(String ref) { ref = mungedRef(ref); if(ref.startsWith("http")||ref.startsWith("https")) { result = RefFormat.URL; - } else if(ref.startsWith("#/")) { + } else if(ref.startsWith(REFERENCE_SEPARATOR)) { result = RefFormat.INTERNAL; - } else if(ref.startsWith(".") || ref.startsWith("/") || ref.indexOf("#/") > 0) { + } else if(ref.startsWith(".") || ref.startsWith("/") || ref.indexOf(REFERENCE_SEPARATOR) > 0) { result = RefFormat.RELATIVE; } @@ -159,7 +177,7 @@ public static String readExternalRef(String file, RefFormat refFormat, List externalPath = RefUtils.getExternalPath(ref); + + // then + assertThat(externalPath.isPresent(), is(false)); + } + + @Test + public void shouldReturnEmptyExternalPathForNullReference() { + // given + String ref = null; + + // when + Optional externalPath = RefUtils.getExternalPath(ref); + + // then + assertThat(externalPath.isPresent(), is(false)); + } + + @Test + public void shouldReturnEmptyExternalPathForEmptyReference() { + // given + String ref = ""; + + // when + Optional externalPath = RefUtils.getExternalPath(ref); + + // then + assertThat(externalPath.isPresent(), is(false)); + } + + @Test + public void shouldReturnEmptyExternalPathForInvalidReference() { + // given + String ref = "test"; + + // when + Optional externalPath = RefUtils.getExternalPath(ref); + + // then + assertThat(externalPath.isPresent(), is(false)); + } + + @Test + public void shouldReturnExternalPathForFileReference() { + // given + String ref = "test.yaml#/components/test"; + + // when + Optional externalPath = RefUtils.getExternalPath(ref); + + // then + assertThat(externalPath.isPresent(), is(true)); + assertThat(externalPath.get(), equalTo("test.yaml")); + } + + @Test + public void shouldReturnExternalPathForHttpReference() { + // given + String ref = "http://localhost/schema.json#/components/test"; + + // when + Optional externalPath = RefUtils.getExternalPath(ref); + + // then + assertThat(externalPath.isPresent(), is(true)); + assertThat(externalPath.get(), equalTo("http://localhost/schema.json")); + } } diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1040/api.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1040/api.yaml new file mode 100644 index 0000000000..e01b1143d1 --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/issue-1040/api.yaml @@ -0,0 +1,16 @@ +openapi: 3.0.0 +info: + title: Test + version: 1.0.0 + +paths: + /value: + get: + operationId: getValues + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: 'lib/lib.yaml#/components/schemas/Value' \ No newline at end of file diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1040/lib/lib.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1040/lib/lib.yaml new file mode 100644 index 0000000000..1818166376 --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/issue-1040/lib/lib.yaml @@ -0,0 +1,13 @@ +components: + schemas: + ValueId: + type: object + properties: + id: + type: integer + format: int64 + Value: + type: object + properties: + id: + $ref: '#/components/schemas/ValueId' \ No newline at end of file