Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,10 @@

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -402,11 +397,33 @@ public void addReferencedKey(String modelKey) {
}

public String getRenamedRef(String originalRef) {
return renameCache.get(originalRef);
return renameCache.get(createRenameCacheKey(originalRef));
}

public void putRenamedRef(String originalRef, String newRef) {
renameCache.put(originalRef, newRef);
renameCache.put(createRenameCacheKey(originalRef), newRef);
}

/**
* Creates a cache key for the rename cache for the provided reference. For consistent comparisons the external part
* is always normalized, e.g. ./components.yaml and components.yaml are considered to reference the same file.
*
* @param originalRef The reference for which we want to create a rename cache key
* @return The appropriate cache key for the reference
*/
private String createRenameCacheKey(String originalRef) {
int separatorIndex = originalRef.indexOf("#/");
if (separatorIndex == -1) {
// Reference doesn't have a local part
return URI.create(originalRef).normalize().toString();
} else if (separatorIndex == 0) {
// Reference doesn't have an external part
return originalRef;
} else {
// Reference with local and external part
URI externalRefURI = URI.create(originalRef.substring(0, separatorIndex));
return externalRefURI.normalize() + originalRef.substring(separatorIndex);
}
}

public Map<String, Object> getResolutionCache() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.file.Path;
import java.util.*;

import static java.util.Arrays.asList;
Expand Down Expand Up @@ -3295,7 +3296,7 @@ public void testIssue1886() {
OpenAPI openAPI = parseResult.getOpenAPI();
assertEqualsNoOrder(
openAPI.getComponents().getSchemas().keySet(),
Arrays.asList("ArrayPojo", "Enum1", "Enum1_1", "Enum2", "Enum3", "MapPojo", "SetPojo", "SimplePojo",
Arrays.asList("ArrayPojo", "Enum1", "Enum2", "Enum3", "MapPojo", "SetPojo", "SimplePojo",
"TransactionsPatchRequestBody", "additional-properties", "array-pojo", "locale-translation-item",
"map-pojo", "set-pojo", "simple-pojo", "translation-item")
);
Expand All @@ -3313,6 +3314,26 @@ public void testIssue2081() {
assertEquals(openAPI.getComponents().getSchemas().get("PetCreate").getProperties().size(), 2);
}

@Test(description = "Should not create duplicate components when using mixed reference patters")
public void testIssue2217ExternalReferenceResolution() {
OpenAPIV3Parser openApiParser = new OpenAPIV3Parser();
ParseOptions options = new ParseOptions();
options.setResolve(true);
options.setFlatten(true);

SwaggerParseResult parseResult = openApiParser.readLocation("issue-2217/main.yaml", null, options);
OpenAPI openAPI = parseResult.getOpenAPI();

Assert.assertNotNull(openAPI, "OpenAPI should be parsed successfully");

// Assert that EmployeeInfo_1 object does not appear in the parsed spec
Assert.assertNotNull(openAPI.getComponents(), "Components should exist");
if (openAPI.getComponents().getSchemas() != null) {
Assert.assertFalse(openAPI.getComponents().getSchemas().containsKey("EmployeeInfo_1"),
"EmployeeInfo_1 should not be created during external reference resolution");
}
}

@Test(description = "responses should be inline")
public void testFullyResolveResponses() {
ParseOptions options = new ParseOptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,33 @@ public void testRenameCache() {
cache.putRenamedRef("foo", "bar");
assertEquals(cache.getRenamedRef("foo"), "bar");
}

@Test
public void testRenameCacheNormalizationExternalAndLocalPart() {
ResolverCache cache = new ResolverCache(openAPI, auths, null);

assertNull(cache.getRenamedRef("./components.yaml#/foo"));
cache.putRenamedRef("./components.yaml#/foo", "bar");
assertEquals(cache.getRenamedRef("./components.yaml#/foo"), "bar");
assertEquals(cache.getRenamedRef("components.yaml#/foo"), "bar");
}

@Test
public void testRenameCacheNormalizationNoLocalPart() {
ResolverCache cache = new ResolverCache(openAPI, auths, null);

assertNull(cache.getRenamedRef("./components.yaml"));
cache.putRenamedRef("./components.yaml", "bar");
assertEquals(cache.getRenamedRef("./components.yaml"), "bar");
assertEquals(cache.getRenamedRef("components.yaml"), "bar");
}

@Test
public void testRenameCacheNormalizationNoExternalPart() {
ResolverCache cache = new ResolverCache(openAPI, auths, null);

assertNull(cache.getRenamedRef("#/foo"));
cache.putRenamedRef("#/foo", "bar");
assertEquals(cache.getRenamedRef("#/foo"), "bar");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
openapi: "3.0.0"
info:
version: 1.1.0
title: fr_fragments
paths: {}
components:
schemas:
CreatedByEmployeeId:
type: string
EmployeesInfoPage:
type: object
properties:
content:
type: array
items:
$ref: '#/components/schemas/EmployeeInfo'
pageResponse:
$ref: pagination.yaml#/components/schemas/PageResponse
ArrayOfGroupsInfo:
type: array
items:
$ref: '#/components/schemas/GroupInfo'
EmployeeInfo:
type: object
properties:
employeeId:
type: string
groupTags:
$ref: '#/components/schemas/ArrayOfGroups'
ArrayOfGroups:
type: array
items:
$ref: '#/components/schemas/GroupTags'
GroupTags:
type: object
properties:
groupTag:
$ref: '#/components/schemas/GroupId'
GroupId:
type: string
PostEmployeeRequest:
$ref: '#/components/schemas/EmployeeInfo'
PutEmployeeRequest:
$ref: '#/components/schemas/EmployeeInfo'
EmployeeIdRequest:
type: object
properties:
employeeId:
type: string
responses:
EmployeeInfo200:
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeeInfo'
EmployeeInfo201:
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeeInfo'
59 changes: 59 additions & 0 deletions modules/swagger-parser-v3/src/test/resources/issue-2217/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
openapi: "3.0.0"
info:
title: Main test
version: 1.1.0
paths:
/int/employees/extended:
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/EmployeesInfoPage'
/int/employees:
post:
requestBody:
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/PostEmployeeRequest'
required: true
responses:
"201":
$ref: 'fragments.yaml#/components/responses/EmployeeInfo201'
/int/employees/id:
put:
requestBody:
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/PutEmployeeRequest'
required: true
responses:
"200":
$ref: 'fragments.yaml#/components/responses/EmployeeInfo200'
"201":
$ref: 'fragments.yaml#/components/responses/EmployeeInfo201'
/int/employees/id/request:
post:
requestBody:
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/EmployeeIdRequest'
required: true
responses:
"200":
$ref: 'fragments.yaml#/components/responses/EmployeeInfo200'
/int/employees/id/remove:
post:
requestBody:
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/EmployeeIdRequest'
required: true
responses:
"204":
description: No Content