diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java index 73cfb051c6..e20831c409 100644 --- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java +++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java @@ -30,6 +30,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -108,17 +109,25 @@ public ResolverCache(OpenAPI openApi, List auths, String par } + private T loadSchemaForInternalRef(String ref, Class expectedType) { + Object loadedRef = loadInternalRef(ref); + + try{ + return expectedType.cast(loadedRef); + } + catch (Exception e) { + return null; + } + } + + private boolean fileIsRootPath(Path file) { + return this.rootPath != null && file.normalize().equals(Paths.get(this.rootPath).toAbsolutePath().normalize()); + } + public T loadRef(String ref, RefFormat refFormat, Class expectedType) { if (refFormat == RefFormat.INTERNAL) { //we don't need to go get anything for internal refs - Object loadedRef = loadInternalRef(ref); - - try{ - return expectedType.cast(loadedRef); - } - catch (Exception e) { - return null; - } + return loadSchemaForInternalRef(ref, expectedType); } final String[] refParts = ref.split("#/"); @@ -130,6 +139,12 @@ public T loadRef(String ref, RefFormat refFormat, Class expectedType) { final String file = refParts[0]; final String definitionPath = refParts.length == 2 ? refParts[1] : null; + if (this.parentDirectory != null && fileIsRootPath(this.parentDirectory.resolve(file))) { + // If the file part of this external ref refers to the same file as the root path, we can treat it like an + // internal ref. + return loadSchemaForInternalRef("#/" + definitionPath, expectedType); + } + //we might have already resolved this ref, so check the resolutionCache Object previouslyResolvedEntity = resolutionCache.get(ref); diff --git a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/ResolverCacheCircularTest.java b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/ResolverCacheCircularTest.java new file mode 100644 index 0000000000..27d162ccdf --- /dev/null +++ b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/ResolverCacheCircularTest.java @@ -0,0 +1,18 @@ +package io.swagger.v3.parser.test; + +import io.swagger.v3.parser.OpenAPIV3Parser; +import io.swagger.v3.parser.core.models.ParseOptions; +import io.swagger.v3.parser.core.models.SwaggerParseResult; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertFalse; + +public class ResolverCacheCircularTest { + @Test + public void testIssue1961_DuplicateSchemas_ABA() throws Exception { + ParseOptions parseOptions = new ParseOptions(); + parseOptions.setResolve(true); + SwaggerParseResult result = new OpenAPIV3Parser().readLocation("src/test/resources/issue-1961/Foo.yaml", null, parseOptions); + assertFalse(result.getOpenAPI().getComponents().getSchemas().containsKey("FooBar_1")); + } +} \ No newline at end of file diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1961/Bar.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1961/Bar.yaml new file mode 100644 index 0000000000..8c84b60281 --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/issue-1961/Bar.yaml @@ -0,0 +1,13 @@ +components: + schemas: + Bar: + anyOf: + - $ref: ./Foo.yaml#/components/schemas/FooBar + BarType: + enum: + - All + - OEM + type: string +info: + title: '#Issue1961.Bar' +openapi: 3.0.1 \ No newline at end of file diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1961/Foo.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1961/Foo.yaml new file mode 100644 index 0000000000..c283724fc6 --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/issue-1961/Foo.yaml @@ -0,0 +1,17 @@ +components: + schemas: + FooBar: + properties: + BypassTypes: + items: + $ref: ./Bar.yaml#/components/schemas/BarType + type: array + type: object + Foo: + properties: + MFABypass: + $ref: ./Bar.yaml#/components/schemas/Bar + type: object +info: + title: '#Issue1961.Foo' +openapi: 3.0.1 \ No newline at end of file