Skip to content

Commit 948a02a

Browse files
authored
Merge branch 'master' into branch_fix_parameter
2 parents 483546e + 87beaa2 commit 948a02a

File tree

15 files changed

+365
-30
lines changed

15 files changed

+365
-30
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Swagger Parser
22

3-
[![Build Status](https://img.shields.io/jenkins/s/https/jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-parser-2.0.svg)](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-parser-2.0)
3+
**NOTE:** If you're looking for `swagger-parser` 1.X and OpenApi 2.0, please refer to [v1 branch](https://github.com/swagger-api/swagger-parser/tree/v1)
4+
5+
[![Build Status](https://img.shields.io/jenkins/s/https/jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-parser-v2.svg)](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-parser-v2)
46

57
## Overview
68
This is the swagger parser project, which reads OpenAPI Specifications into current Java POJOs. It also provides a simple framework to add additional converters from different formats into the Swagger objects, making the entire toolchain available.
@@ -97,7 +99,7 @@ You can include this library from Sonatype OSS for SNAPSHOTS, or Maven central f
9799
<dependency>
98100
<groupId>io.swagger.parser.v3</groupId>
99101
<artifactId>swagger-parser</artifactId>
100-
<version>2.0.5</version>
102+
<version>2.0.6-SNAPSHOT</version>
101103
</dependency>
102104

103105
```
@@ -108,7 +110,7 @@ or
108110
<dependency>
109111
<groupId>io.swagger.parser.v3</groupId>
110112
<artifactId>swagger-parser</artifactId>
111-
<version>2.0.5</version>
113+
<version>2.0.6-SNAPSHOT</version>
112114
</dependency>
113115

114116
```

modules/swagger-parser-core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>io.swagger.parser.v3</groupId>
55
<artifactId>swagger-parser-project</artifactId>
6-
<version>2.0.5</version>
6+
<version>2.0.6-SNAPSHOT</version>
77
<relativePath>../..</relativePath>
88
</parent>
99
<modelVersion>4.0.0</modelVersion>

modules/swagger-parser-v2-converter/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>io.swagger.parser.v3</groupId>
55
<artifactId>swagger-parser-project</artifactId>
6-
<version>2.0.5</version>
6+
<version>2.0.6-SNAPSHOT</version>
77
<relativePath>../..</relativePath>
88
</parent>
99
<modelVersion>4.0.0</modelVersion>

modules/swagger-parser-v3/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>io.swagger.parser.v3</groupId>
55
<artifactId>swagger-parser-project</artifactId>
6-
<version>2.0.5</version>
6+
<version>2.0.6-SNAPSHOT</version>
77
<relativePath>../..</relativePath>
88
</parent>
99
<modelVersion>4.0.0</modelVersion>

modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,7 @@
5252
import java.net.URI;
5353
import java.net.URISyntaxException;
5454
import java.net.URL;
55-
import java.util.ArrayList;
56-
import java.util.Arrays;
57-
import java.util.Iterator;
58-
import java.util.LinkedHashMap;
59-
import java.util.LinkedHashSet;
60-
import java.util.List;
61-
import java.util.Map;
62-
import java.util.Optional;
63-
import java.util.Set;
55+
import java.util.*;
6456
import java.util.stream.Collectors;
6557
import java.util.stream.Stream;
6658

@@ -98,6 +90,7 @@ public class OpenAPIDeserializer {
9890
private static final String PATH_PARAMETER = "path";
9991
private static final String HEADER_PARAMETER = "header";
10092

93+
private final Set<String> operationIDs = new HashSet<>();
10194

10295
public SwaggerParseResult deserialize(JsonNode rootNode) {
10396
return deserialize(rootNode, null);
@@ -687,7 +680,7 @@ public ExternalDocumentation getExternalDocs(ObjectNode node, String location, P
687680
}
688681

689682

690-
public String getString(String key, ObjectNode node, boolean required, String location, ParseResult result) {
683+
public String getString(String key, ObjectNode node, boolean required, String location, ParseResult result, Set<String> uniqueValues) {
691684
String value = null;
692685
JsonNode v = node.get(key);
693686
if (node == null || v == null) {
@@ -699,10 +692,18 @@ public String getString(String key, ObjectNode node, boolean required, String lo
699692
result.invalidType(location, key, "string", node);
700693
} else {
701694
value = v.asText();
695+
if (uniqueValues != null && !uniqueValues.add(value)) {
696+
result.unique(location, "operationId");
697+
result.invalid();
698+
}
702699
}
703700
return value;
704701
}
705702

703+
public String getString(String key, ObjectNode node, boolean required, String location, ParseResult result) {
704+
return getString(key, node, required, location, result, null);
705+
}
706+
706707
public Set<String> getKeys(ObjectNode node) {
707708
Set<String> keys = new LinkedHashSet<>();
708709
if (node == null) {
@@ -1050,6 +1051,11 @@ public Link getLink(ObjectNode linkNode, String location, ParseResult result) {
10501051
link.setParameters(getLinkParameters(parametersObject, location, result));
10511052
}
10521053

1054+
String requestBody = getString("requestBody",linkNode,false,location,result);
1055+
if (requestBody!= null) {
1056+
link.setRequestBody(requestBody);
1057+
}
1058+
10531059
ObjectNode headerObject = getObject("headers",linkNode,false,location,result);
10541060
if (headerObject!= null) {
10551061
link.setHeaders(getHeaders(headerObject, location, result));
@@ -1122,14 +1128,13 @@ public Callback getCallback(ObjectNode node,String location, ParseResult result)
11221128
JsonNode ref = node.get("$ref");
11231129
if (ref != null) {
11241130
if (ref.getNodeType().equals(JsonNodeType.STRING)) {
1125-
PathItem pathItem = new PathItem();
11261131
String mungedRef = mungedRef(ref.textValue());
11271132
if (mungedRef != null) {
1128-
pathItem.set$ref(mungedRef);
1133+
callback.set$ref(mungedRef);
11291134
}else{
1130-
pathItem.set$ref(ref.textValue());
1135+
callback.set$ref(ref.textValue());
11311136
}
1132-
return callback.addPathItem(name,pathItem);
1137+
return callback;
11331138
} else {
11341139
result.invalidType(location, "$ref", "string", node);
11351140
return null;
@@ -2455,7 +2460,7 @@ public Operation getOperation(ObjectNode obj, String location, ParseResult resul
24552460
if(docs != null) {
24562461
operation.setExternalDocs(docs);
24572462
}
2458-
value = getString("operationId", obj, false, location, result);
2463+
value = getString("operationId", obj, false, location, result, operationIDs);
24592464
if (StringUtils.isNotBlank(value)) {
24602465
operation.operationId(value);
24612466
}
@@ -2670,6 +2675,7 @@ protected static class ParseResult {
26702675
private Map<Location, JsonNode> unsupported = new LinkedHashMap<>();
26712676
private Map<Location, String> invalidType = new LinkedHashMap<>();
26722677
private List<Location> missing = new ArrayList<>();
2678+
private List<Location> unique = new ArrayList<>();
26732679

26742680
public ParseResult() {
26752681
}
@@ -2686,6 +2692,10 @@ public void missing(String location, String key) {
26862692
missing.add(new Location(location, key));
26872693
}
26882694

2695+
public void unique(String location, String key) {
2696+
unique.add(new Location(location, key));
2697+
}
2698+
26892699
public void invalidType(String location, String key, String expectedType, JsonNode value) {
26902700
invalidType.put(new Location(location, key), expectedType);
26912701
}
@@ -2720,6 +2730,11 @@ public List<String> getMessages() {
27202730
String message = "attribute " + location + l.key + " is unsupported";
27212731
messages.add(message);
27222732
}
2733+
for (Location l : unique) {
2734+
String location = l.location.equals("") ? "" : l.location + ".";
2735+
String message = "attribute " + location + l.key + " is repeated";
2736+
messages.add(message);
2737+
}
27232738
return messages;
27242739
}
27252740
}

modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.swagger.v3.oas.models.PathItem;
66
import io.swagger.v3.oas.models.callbacks.Callback;
77
import io.swagger.v3.oas.models.examples.Example;
8+
import io.swagger.v3.oas.models.links.Link;
89
import io.swagger.v3.oas.models.media.ArraySchema;
910
import io.swagger.v3.oas.models.media.ComposedSchema;
1011
import io.swagger.v3.oas.models.media.MediaType;
@@ -13,6 +14,7 @@
1314
import io.swagger.v3.oas.models.parameters.Parameter;
1415
import io.swagger.v3.oas.models.parameters.RequestBody;
1516
import io.swagger.v3.oas.models.responses.ApiResponse;
17+
import io.swagger.v3.oas.models.responses.ApiResponses;
1618
import io.swagger.v3.parser.models.RefFormat;
1719
import org.slf4j.Logger;
1820
import org.slf4j.LoggerFactory;
@@ -49,7 +51,7 @@ public ResolverFully(boolean aggregateCombinators) {
4951
private Map<String, Example> examples;
5052
private Map<String, Parameter> parameters;
5153
private Map<String, RequestBody> requestBodies;
52-
54+
private Map<String, Link> links;
5355

5456
public void resolveFully(OpenAPI openAPI) {
5557
if (openAPI.getComponents() != null && openAPI.getComponents().getRequestBodies() != null) {
@@ -73,12 +75,20 @@ public void resolveFully(OpenAPI openAPI) {
7375
}
7476
}
7577

78+
7679
if (openAPI.getComponents() != null && openAPI.getComponents().getParameters() != null) {
7780
parameters = openAPI.getComponents().getParameters();
7881
if (parameters == null) {
7982
parameters = new HashMap<>();
8083
}
8184
}
85+
if (openAPI.getComponents() != null && openAPI.getComponents().getLinks() != null) {
86+
links = openAPI.getComponents().getLinks();
87+
if (links == null) {
88+
links = new HashMap<>();
89+
90+
}
91+
}
8292

8393
if(openAPI.getPaths() != null) {
8494
for (String pathname : openAPI.getPaths().keySet()) {
@@ -147,9 +157,10 @@ public void resolvePath(PathItem pathItem){
147157
}
148158
}
149159
// responses
150-
if(op.getResponses() != null) {
151-
for(String code : op.getResponses().keySet()) {
152-
ApiResponse response = op.getResponses().get(code);
160+
ApiResponses responses = op.getResponses();
161+
if(responses != null) {
162+
for(String code : responses.keySet()) {
163+
ApiResponse response = responses.get(code);
153164
if (response.getContent() != null) {
154165
Map<String, MediaType> content = response.getContent();
155166
for(String mediaType: content.keySet()){
@@ -164,11 +175,31 @@ public void resolvePath(PathItem pathItem){
164175
}
165176
}
166177
}
178+
Map<String, Link> links = response.getLinks();
179+
if (links != null) {
180+
for (Map.Entry<String, Link> link : links.entrySet()) {
181+
Link value = link.getValue();
182+
Link resolvedValue = value.get$ref() != null ? resolveLink(value) : value;
183+
link.setValue(resolvedValue);
184+
}
185+
}
167186
}
168187
}
169188
}
170189
}
171190

191+
public Link resolveLink(Link link){
192+
RefFormat refFormat = computeRefFormat(link.get$ref());
193+
String $ref = link.get$ref();
194+
if (!isAnExternalRefFormat(refFormat)){
195+
if (links != null && !links.isEmpty()) {
196+
String referenceKey = computeDefinitionName($ref);
197+
return links.getOrDefault(referenceKey, link);
198+
}
199+
}
200+
return link;
201+
}
202+
172203
public RequestBody resolveRequestBody(RequestBody requestBody){
173204
RefFormat refFormat = computeRefFormat(requestBody.get$ref());
174205
String $ref = requestBody.get$ref();

modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIResolverTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,11 @@ public void componentsResolver() throws Exception {
339339

340340
Map<String, Callback> callbacks = openAPI.getComponents().getCallbacks();
341341
// internal callback reference
342-
assertEquals(callbacks.get("referenced").get("$ref").get$ref(),"#/components/callbacks/failed");
342+
assertEquals(callbacks.get("referenced").get$ref(),"#/components/callbacks/failed");
343343
//callback pathItem -> operation ->requestBody
344344
assertEquals(callbacks.get("heartbeat").get("$request.query.heartbeat-url").getPost().getRequestBody().get$ref(),"#/components/requestBodies/requestBody3");
345345
//remote callback ref
346-
assertEquals(callbacks.get("remoteCallback").get("$ref").get$ref(),"#/components/callbacks/callback");
346+
assertEquals(callbacks.get("remoteCallback").get$ref(),"http://localhost:" + serverPort + "/remote/callback");
347347

348348
}
349349

modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.swagger.v3.oas.models.OpenAPI;
1313
import io.swagger.v3.oas.models.Operation;
1414
import io.swagger.v3.oas.models.PathItem;
15+
import io.swagger.v3.oas.models.links.Link;
1516
import io.swagger.v3.oas.models.media.*;
1617
import io.swagger.v3.oas.models.examples.Example;
1718
import io.swagger.v3.oas.models.media.ArraySchema;
@@ -1547,6 +1548,26 @@ public void shouldParseParameters() {
15471548
assertEquals(parameter.getIn(), "path");
15481549
assertEquals(parameter.getName(), "playerId");
15491550
}
1551+
1552+
@Test
1553+
public void testIssue884() {
1554+
ParseOptions parseOptions = new ParseOptions();
1555+
parseOptions.setResolveFully(true);
1556+
OpenAPI openAPI = new OpenAPIV3Parser().read("src/test/resources/issue_884.yaml", null, parseOptions);
1557+
Map<String, Link> links = openAPI.getPaths().get("/2.0/repositories/{username}").getGet().getResponses().get("200").getLinks();
1558+
String operationId = links.get("userRepository").getOperationId();
1559+
assertEquals(operationId, "getRepository");
1560+
}
1561+
1562+
@Test
1563+
public void testLinkIssue() {
1564+
ParseOptions parseOptions = new ParseOptions();
1565+
parseOptions.setResolveFully(true);
1566+
OpenAPI openAPI = new OpenAPIV3Parser().read("src/test/resources/linkIssue.yaml", null, parseOptions);
1567+
Map<String, Link> links = openAPI.getPaths().get("/2.0/repositories/{username}").getGet().getResponses().get("200").getLinks();
1568+
Object requestBody = links.get("userRepository").getRequestBody();
1569+
assertEquals(requestBody, "$response.body#/slug");
1570+
}
15501571

15511572
private static int getDynamicPort() {
15521573
return new Random().ints(10000, 20000).findFirst().getAsInt();
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
openapi: 3.0.0
2+
info:
3+
title: Link Example
4+
version: 1.0.0
5+
paths:
6+
/2.0/repositories/{username}:
7+
get:
8+
operationId: getRepositoriesByOwner
9+
parameters:
10+
- name: username
11+
in: path
12+
required: true
13+
schema:
14+
type: string
15+
responses:
16+
'200':
17+
description: repositories owned by the supplied user
18+
content:
19+
application/json:
20+
schema:
21+
type: array
22+
items:
23+
$ref: '#/components/schemas/repository'
24+
links:
25+
userRepository:
26+
$ref: '#/components/links/userRepository'
27+
/2.0/repositories/{username}/{slug}:
28+
get:
29+
operationId: getRepository
30+
parameters:
31+
- name: username
32+
in: path
33+
required: true
34+
schema:
35+
type: string
36+
- name: slug
37+
in: path
38+
required: true
39+
schema:
40+
type: string
41+
responses:
42+
'200':
43+
description: The repository
44+
content:
45+
application/json:
46+
schema:
47+
$ref: '#/components/schemas/repository'
48+
components:
49+
links:
50+
userRepository:
51+
operationId: getRepository
52+
requestBody: '$response.body#/slug'
53+
schemas:
54+
user:
55+
type: object
56+
properties:
57+
username:
58+
type: string
59+
uuid:
60+
type: string
61+
repository:
62+
type: object
63+
properties:
64+
slug:
65+
type: string
66+
owner:
67+
$ref: '#/components/schemas/user'
68+
pullrequest:
69+
type: object
70+
properties:
71+
id:
72+
type: integer
73+
title:
74+
type: string
75+
repository:
76+
$ref: '#/components/schemas/repository'
77+
author:
78+
$ref: '#/components/schemas/user'

0 commit comments

Comments
 (0)