Skip to content

Commit 6a0f9dd

Browse files
committed
Use Jackson for deserialization instead use io.swagger.parser.v3
Signed-off-by: Matheus Cruz <[email protected]>
1 parent e478978 commit 6a0f9dd

File tree

8 files changed

+454
-242
lines changed

8 files changed

+454
-242
lines changed

impl/openapi/pom.xml

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@
77
</parent>
88
<artifactId>serverlessworkflow-impl-openapi</artifactId>
99
<name>Serverless Workflow :: Impl :: OpenAPI</name>
10-
11-
<properties>
12-
<version.org.mozilla.rhino>1.9.0</version.org.mozilla.rhino>
13-
<version.org.apache.commons.lang3>3.20.0</version.org.apache.commons.lang3>
14-
<version.commons.codec>1.20.0</version.commons.codec>
15-
</properties>
16-
1710
<dependencies>
1811
<dependency>
1912
<groupId>jakarta.ws.rs</groupId>
@@ -25,32 +18,12 @@
2518
</dependency>
2619
<dependency>
2720
<groupId>io.serverlessworkflow</groupId>
28-
<artifactId>serverlessworkflow-impl-http</artifactId>
29-
</dependency>
30-
<dependency>
31-
<groupId>io.swagger.parser.v3</groupId>
32-
<artifactId>swagger-parser</artifactId>
33-
<version>${version.io.swagger.parser.v3}</version>
34-
</dependency>
35-
36-
<!-- Swagger Parser brings a few dependencies with CVE, we are breaking them here -->
37-
<!-- Once they upgrade, we can remove -->
38-
<dependency>
39-
<groupId>org.mozilla</groupId>
40-
<artifactId>rhino</artifactId>
41-
<version>${version.org.mozilla.rhino}</version>
21+
<artifactId>serverlessworkflow-api</artifactId>
4222
</dependency>
4323
<dependency>
44-
<groupId>org.apache.commons</groupId>
45-
<artifactId>commons-lang3</artifactId>
46-
<version>${version.org.apache.commons.lang3}</version>
47-
</dependency>
48-
<dependency>
49-
<groupId>commons-codec</groupId>
50-
<artifactId>commons-codec</artifactId>
51-
<version>${version.commons.codec}</version>
24+
<groupId>io.serverlessworkflow</groupId>
25+
<artifactId>serverlessworkflow-impl-http</artifactId>
5226
</dependency>
53-
5427
<dependency>
5528
<groupId>org.junit.jupiter</groupId>
5629
<artifactId>junit-jupiter-engine</artifactId>
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.impl.executors.openapi;
17+
18+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19+
import com.fasterxml.jackson.annotation.JsonProperty;
20+
import com.fasterxml.jackson.databind.JsonNode;
21+
22+
import java.util.List;
23+
import java.util.Locale;
24+
import java.util.Map;
25+
import java.util.Objects;
26+
import java.util.Optional;
27+
import java.util.Set;
28+
29+
@JsonIgnoreProperties(ignoreUnknown = true)
30+
public record MinimalOpenAPI(
31+
String swagger,
32+
List<Server> servers,
33+
String host,
34+
String basePath,
35+
List<String> schemes,
36+
Map<String, PathItem> paths,
37+
Components components,
38+
Map<String, Schema> definitions) {
39+
40+
public enum SwaggerVersion {
41+
SWAGGER_V2,
42+
OPENAPI_V3
43+
}
44+
45+
public SwaggerVersion swaggerVersion() {
46+
return isSwaggerV2() ? SwaggerVersion.SWAGGER_V2 : SwaggerVersion.OPENAPI_V3;
47+
}
48+
49+
private boolean isSwaggerV2() {
50+
return swagger != null && swagger.trim().startsWith("2.");
51+
}
52+
53+
Optional<OperationDefinition> findOperationById(String operationId) {
54+
if (paths == null || operationId == null) {
55+
return Optional.empty();
56+
}
57+
58+
for (var entry : paths.entrySet()) {
59+
String path = entry.getKey();
60+
PathItem pathItem = entry.getValue();
61+
62+
for (var httpOperation : pathItem.methods()) {
63+
if (httpOperation.operation() != null
64+
&& operationId.equals(httpOperation.operation().operationId())) {
65+
return Optional.of(
66+
new OperationDefinition(
67+
this,
68+
httpOperation.operation(),
69+
path,
70+
httpOperation.method().toUpperCase(Locale.ROOT)));
71+
}
72+
}
73+
}
74+
return Optional.empty();
75+
}
76+
77+
public List<String> getServers() {
78+
if (swaggerVersion() == SwaggerVersion.SWAGGER_V2) {
79+
if (host == null || host.isBlank()) {
80+
return List.of();
81+
}
82+
83+
String base = host;
84+
if (basePath != null && !basePath.isBlank()) {
85+
base += basePath;
86+
}
87+
88+
return List.of(schemes.stream().findFirst().orElse("https") + "://" + base);
89+
}
90+
91+
if (servers == null || servers.isEmpty()) {
92+
return List.of();
93+
}
94+
95+
return servers.stream().map(Server::url).toList();
96+
}
97+
98+
/**
99+
* Resolves a schema reference to a Schema object.
100+
*
101+
* <p>It does not resolve nested references.
102+
*/
103+
public Schema resolveSchema(String ref) {
104+
if (isSwaggerV2()) {
105+
return resolveRefSwaggerV2(ref);
106+
} else {
107+
return resolveRefOpenAPI(ref);
108+
}
109+
}
110+
111+
private Schema resolveRefOpenAPI(String ref) {
112+
if (ref == null || !ref.startsWith("#/components/schemas/")) {
113+
return null;
114+
}
115+
116+
if (components == null || components.schemas() == null) {
117+
return null;
118+
}
119+
120+
String name = ref.substring("#/components/schemas/".length());
121+
return components.schemas().get(name);
122+
}
123+
124+
private Schema resolveRefSwaggerV2(String ref) {
125+
if (ref == null || !ref.startsWith("#/definitions/")) {
126+
return null;
127+
}
128+
129+
if (definitions == null) {
130+
return null;
131+
}
132+
133+
String name = ref.substring("#/definitions/".length());
134+
135+
return definitions.get(name);
136+
}
137+
138+
@JsonIgnoreProperties(ignoreUnknown = true)
139+
public record Server(String url) {}
140+
141+
@JsonIgnoreProperties(ignoreUnknown = true)
142+
public static final class PathItem {
143+
private final Operation get;
144+
private final Operation post;
145+
private final Operation put;
146+
private final Operation delete;
147+
private final Operation patch;
148+
private final Operation head;
149+
private final Operation options;
150+
private final Set<HttpOperation> methods;
151+
152+
public PathItem(
153+
Operation get,
154+
Operation post,
155+
Operation put,
156+
Operation delete,
157+
Operation patch,
158+
Operation head,
159+
Operation options) {
160+
this.get = get;
161+
this.post = post;
162+
this.put = put;
163+
this.delete = delete;
164+
this.patch = patch;
165+
this.head = head;
166+
this.options = options;
167+
this.methods = buildMethods();
168+
}
169+
170+
private Set<HttpOperation> buildMethods() {
171+
return Set.of(
172+
new HttpOperation("get", get),
173+
new HttpOperation("post", post),
174+
new HttpOperation("put", put),
175+
new HttpOperation("delete", delete),
176+
new HttpOperation("patch", patch),
177+
new HttpOperation("head", head),
178+
new HttpOperation("options", options));
179+
}
180+
181+
Set<HttpOperation> methods() {
182+
return Set.copyOf(methods);
183+
}
184+
185+
public Operation get() {
186+
return get;
187+
}
188+
189+
public Operation post() {
190+
return post;
191+
}
192+
193+
public Operation put() {
194+
return put;
195+
}
196+
197+
public Operation delete() {
198+
return delete;
199+
}
200+
201+
public Operation patch() {
202+
return patch;
203+
}
204+
205+
public Operation head() {
206+
return head;
207+
}
208+
209+
public Operation options() {
210+
return options;
211+
}
212+
213+
@Override
214+
public boolean equals(Object obj) {
215+
if (obj == this) return true;
216+
if (obj == null || obj.getClass() != this.getClass()) return false;
217+
var that = (PathItem) obj;
218+
return Objects.equals(this.get, that.get) &&
219+
Objects.equals(this.post, that.post) &&
220+
Objects.equals(this.put, that.put) &&
221+
Objects.equals(this.delete, that.delete) &&
222+
Objects.equals(this.patch, that.patch) &&
223+
Objects.equals(this.head, that.head) &&
224+
Objects.equals(this.options, that.options);
225+
}
226+
227+
@Override
228+
public int hashCode() {
229+
return Objects.hash(get, post, put, delete, patch, head, options);
230+
}
231+
}
232+
233+
@JsonIgnoreProperties(ignoreUnknown = true)
234+
record HttpOperation(String method, Operation operation) {}
235+
236+
@JsonIgnoreProperties(ignoreUnknown = true)
237+
public record Operation(String operationId, List<Parameter> parameters, RequestBody requestBody) {
238+
239+
public boolean hasParameters() {
240+
return parameters != null && !parameters.isEmpty();
241+
}
242+
243+
public boolean hasRequestBody() {
244+
return requestBody != null;
245+
}
246+
}
247+
248+
@JsonIgnoreProperties(ignoreUnknown = true)
249+
public record Parameter(String name, String in, Boolean required, Schema schema) {}
250+
251+
@JsonIgnoreProperties(ignoreUnknown = true)
252+
public record RequestBody(Content content) {}
253+
254+
@JsonIgnoreProperties(ignoreUnknown = true)
255+
public record Content(@JsonProperty("application/json") MediaType applicationJson) {
256+
public boolean isApplicationJson() {
257+
return applicationJson != null;
258+
}
259+
}
260+
261+
@JsonIgnoreProperties(ignoreUnknown = true)
262+
public record MediaType(Schema schema) {}
263+
264+
@JsonIgnoreProperties(ignoreUnknown = true)
265+
public record Components(Map<String, Schema> schemas) {}
266+
267+
@JsonIgnoreProperties(ignoreUnknown = true)
268+
public record Definitions(Map<String, Schema> definitions) {}
269+
270+
@JsonIgnoreProperties(ignoreUnknown = true)
271+
public record Schema(
272+
String type,
273+
Map<String, Schema> properties,
274+
List<String> required,
275+
@JsonProperty("$ref") String ref,
276+
@JsonProperty("default") JsonNode _default) {
277+
278+
public boolean hasRef() {
279+
return ref != null && !ref.isBlank();
280+
}
281+
282+
public boolean hasProperties() {
283+
return properties != null && !properties.isEmpty();
284+
}
285+
286+
public Set<String> requiredFields() {
287+
return required == null ? Set.of() : Set.copyOf(required);
288+
}
289+
}
290+
}

0 commit comments

Comments
 (0)