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 286f9ccac9..67ad3ffda6 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 @@ -125,7 +125,7 @@ public String processRefToExternalSchema(String $ref, RefFormat refFormat) { if (!ref.equals(RefFormat.URL)) { String schemaFullRef = schema.get$ref(); String parent = (file.contains("/")) ? file.substring(0, file.lastIndexOf('/')) : ""; - if (!parent.isEmpty()) { + if (!parent.isEmpty() && !schemaFullRef.startsWith("/")) { if (schemaFullRef.contains("#/")) { String[] parts = schemaFullRef.split("#/"); String schemaFullRefFilePart = parts[0]; diff --git a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java index c46c320ce4..d3349aec26 100644 --- a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java +++ b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java @@ -3398,6 +3398,26 @@ public void testValidateExternalRefsTrue() { } + @Test(description = "test that a model in a folder that has a ref to a model in the classpath is properly resolved.") + public void testIssue1891() { + ParseOptions options = new ParseOptions(); + options.setResolve(true); + options.setFlatten(true); + + SwaggerParseResult result = new OpenAPIV3Parser().readLocation("./issue-1891/openapi.yaml", null, options); + assertTrue(result.getMessages().isEmpty()); + + // Expect all references to be properly resolved to local references. + OpenAPI openAPI = result.getOpenAPI(); + Schema localModel = openAPI.getComponents().getSchemas().get("LocalModel"); + Schema typesModel = openAPI.getComponents().getSchemas().get("TypesModel"); + Schema sharedModel = openAPI.getComponents().getSchemas().get("SharedModel"); + + assertEquals("#/components/schemas/TypesModel", localModel.getProperties().get("sharedModelField").get$ref()); + assertEquals("#/components/schemas/SharedModel", typesModel.get$ref()); + assertNotNull(sharedModel); + } + @Test(description = "directly parsed definition, tested in previous method as reference relative/local ") public void testValidateDefinition() { ParseOptions options = new ParseOptions(); diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1891-shared-types.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1891-shared-types.yaml new file mode 100644 index 0000000000..2be9b0db89 --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/issue-1891-shared-types.yaml @@ -0,0 +1,22 @@ +--- +openapi: 3.0.0 + +info: + description: Models that would published in a jar and then read from the classpath. + version: 1.0.0 + title: shared-types + +paths: + /empty: + description: > + Empty API so that we can load this file in Swagger Editor for validation and + not get flagged for a contract without a paths element. + +components: + schemas: + SharedModel: + description: A shared model + type: object + properties: + name: + type: string diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1891/openapi.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1891/openapi.yaml new file mode 100644 index 0000000000..fc794d8cf2 --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/issue-1891/openapi.yaml @@ -0,0 +1,22 @@ +--- +openapi: 3.0.0 + +info: + description: Models that would published in a jar and then read from the classpath. + version: 1.0.0 + title: shared-models + +paths: + /empty: + description: > + Empty API so that we can load this file in Swagger Editor for validation and + not get flagged for a contract without a paths element. + +components: + schemas: + LocalModel: + type: object + properties: + sharedModelField: + # This is resolved via the file system, but looking in the folder 'types' + $ref: 'types/local-types.yaml#/components/schemas/TypesModel' diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1891/types/local-types.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1891/types/local-types.yaml new file mode 100644 index 0000000000..d2d07854cb --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/issue-1891/types/local-types.yaml @@ -0,0 +1,22 @@ +--- +openapi: 3.0.0 + +info: + description: Models that would published in a jar and then read from the classpath. + version: 1.0.0 + title: shared-models + +paths: + /empty: + description: > + Empty API so that we can load this file in Swagger Editor for validation and + not get flagged for a contract without a paths element. + +components: + schemas: + TypesModel: + # The file 'issue-1891-shared-types.yaml' is located outside this directory and resolved + # via an absolute path reference (starts with a /). Typically, this resource would be + # found in a jar file on the classpath, but for the purposes of this test, it is + # found at the root of the file system, which will be loaded via the classpath helper. + $ref: '/issue-1891-shared-types.yaml#/components/schemas/SharedModel'