Skip to content

Commit 3458f4f

Browse files
committed
Jakarta flavor of bootique-swagger #31
1 parent d064bb7 commit 3458f4f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2360
-91
lines changed

bootique-swagger-jakarta/pom.xml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Licensed to ObjectStyle LLC under one
4+
or more contributor license agreements. See the NOTICE file
5+
distributed with this work for additional information
6+
regarding copyright ownership. The ObjectStyle LLC licenses
7+
this file to you under the Apache License, Version 2.0 (the
8+
"License"); you may not use this file except in compliance
9+
with the License. You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing,
14+
software distributed under the License is distributed on an
15+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
KIND, either express or implied. See the License for the
17+
specific language governing permissions and limitations
18+
under the License.
19+
-->
20+
21+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
<parent>
24+
<artifactId>bootique-swagger-parent</artifactId>
25+
<groupId>io.bootique.swagger</groupId>
26+
<version>3.0.M1-SNAPSHOT</version>
27+
</parent>
28+
<modelVersion>4.0.0</modelVersion>
29+
30+
<artifactId>bootique-swagger-jakarta</artifactId>
31+
<packaging>jar</packaging>
32+
33+
<name>bootique-swagger-jakarta: Swagger-based OpenAPI Integration with Bootique and Jersey (Jakarta)</name>
34+
<description>Provides Swagger-based OpenAPI integration with Bootique and Jersey (Jakarta flavor)</description>
35+
36+
<!--
37+
For some reason sharing these dependency management declarations in the parent POM causes Javax module failures,
38+
so we should keep it here
39+
-->
40+
<dependencyManagement>
41+
<dependencies>
42+
<dependency>
43+
<groupId>io.bootique.jetty</groupId>
44+
<artifactId>bootique-jetty-jakarta</artifactId>
45+
<version>${bootique.version}</version>
46+
</dependency>
47+
<dependency>
48+
<groupId>io.bootique.jetty</groupId>
49+
<artifactId>bootique-jetty-jakarta-junit5</artifactId>
50+
<version>${bootique.version}</version>
51+
</dependency>
52+
<dependency>
53+
<groupId>io.bootique.jersey</groupId>
54+
<artifactId>bootique-jersey-jakarta</artifactId>
55+
<version>${bootique.version}</version>
56+
</dependency>
57+
<dependency>
58+
<groupId>io.swagger.core.v3</groupId>
59+
<artifactId>swagger-jaxrs2-jakarta</artifactId>
60+
<version>${swagger.version}</version>
61+
<exclusions>
62+
<!-- Most of these are dependencies of "swagger-core". Relying on recursive exclusion -->
63+
<!-- Jersey uses Jakarta Validation 2.x elsewhere, so excluding old 1.x -->
64+
<exclusion>
65+
<groupId>jakarta.validation</groupId>
66+
<artifactId>validation-api</artifactId>
67+
</exclusion>
68+
<exclusion>
69+
<groupId>jakarta.xml.bind</groupId>
70+
<artifactId>jakarta.xml.bind-api</artifactId>
71+
</exclusion>
72+
<exclusion>
73+
<groupId>com.fasterxml.jackson.datatype</groupId>
74+
<artifactId>jackson-datatype-jsr310</artifactId>
75+
</exclusion>
76+
<exclusion>
77+
<groupId>jakarta.activation</groupId>
78+
<artifactId>jakarta.activation-api</artifactId>
79+
</exclusion>
80+
</exclusions>
81+
</dependency>
82+
</dependencies>
83+
</dependencyManagement>
84+
85+
<dependencies>
86+
<!-- Compile dependencies -->
87+
<dependency>
88+
<groupId>io.bootique.jersey</groupId>
89+
<artifactId>bootique-jersey-jakarta</artifactId>
90+
<scope>compile</scope>
91+
</dependency>
92+
<dependency>
93+
<groupId>io.swagger.core.v3</groupId>
94+
<artifactId>swagger-jaxrs2-jakarta</artifactId>
95+
<scope>compile</scope>
96+
</dependency>
97+
<!-- Override the wrong version of "jackson-datatype-jsr310" in swagger-core -->
98+
<dependency>
99+
<groupId>com.fasterxml.jackson.datatype</groupId>
100+
<artifactId>jackson-datatype-jsr310</artifactId>
101+
<scope>compile</scope>
102+
</dependency>
103+
104+
<!-- Unit test dependencies -->
105+
<dependency>
106+
<groupId>io.bootique.jetty</groupId>
107+
<artifactId>bootique-jetty-jakarta-junit5</artifactId>
108+
<scope>test</scope>
109+
</dependency>
110+
<dependency>
111+
<groupId>org.mockito</groupId>
112+
<artifactId>mockito-core</artifactId>
113+
<scope>test</scope>
114+
</dependency>
115+
<dependency>
116+
<groupId>org.slf4j</groupId>
117+
<artifactId>slf4j-simple</artifactId>
118+
<scope>test</scope>
119+
</dependency>
120+
</dependencies>
121+
122+
</project>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Licensed to ObjectStyle LLC under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ObjectStyle LLC licenses
6+
* this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package io.bootique.swagger.jakarta;
20+
21+
import io.swagger.v3.core.converter.AnnotatedType;
22+
import io.swagger.v3.core.converter.ModelConverter;
23+
import io.swagger.v3.core.converter.ModelConverterContext;
24+
import io.swagger.v3.core.util.RefUtils;
25+
import io.swagger.v3.oas.models.media.Schema;
26+
27+
import java.util.Iterator;
28+
29+
/**
30+
* A convenience superclass for custom model converters that simplifies type detection.
31+
*
32+
* @since 2.0.B1
33+
*/
34+
public abstract class BaseModelConverter implements ModelConverter {
35+
36+
@Override
37+
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
38+
39+
Schema existing = context.resolve(type);
40+
if (existing != null) {
41+
return existing;
42+
}
43+
44+
TypeWrapper wrapped = TypeWrapper.forType(type.getType());
45+
return willResolve(type, context, wrapped)
46+
? doResolve(type, context, chain, wrapped)
47+
: delegateResolve(type, context, chain);
48+
}
49+
50+
protected abstract boolean willResolve(AnnotatedType type, ModelConverterContext context, TypeWrapper wrapped);
51+
52+
protected abstract Schema doResolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain, TypeWrapper wrapped);
53+
54+
protected Schema delegateResolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
55+
return chain.hasNext() ? chain.next().resolve(type, context, chain) : null;
56+
}
57+
58+
protected Schema onSchemaResolved(AnnotatedType type, ModelConverterContext context, Schema resolved) {
59+
return type.isResolveAsRef()
60+
? new Schema().$ref(RefUtils.constructRef(resolved.getName()))
61+
: resolved;
62+
}
63+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Licensed to ObjectStyle LLC under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ObjectStyle LLC licenses
6+
* this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package io.bootique.swagger.jakarta;
20+
21+
import com.fasterxml.jackson.databind.ObjectMapper;
22+
import io.swagger.v3.core.util.Json;
23+
import io.swagger.v3.core.util.Yaml;
24+
import io.swagger.v3.jaxrs2.Reader;
25+
import io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner;
26+
import io.swagger.v3.oas.integration.SwaggerConfiguration;
27+
import io.swagger.v3.oas.models.OpenAPI;
28+
import io.swagger.v3.oas.models.Paths;
29+
import jakarta.ws.rs.core.Application;
30+
31+
import java.io.IOException;
32+
import java.net.URL;
33+
import java.util.Arrays;
34+
import java.util.HashSet;
35+
import java.util.List;
36+
37+
/**
38+
* @since 2.0
39+
*/
40+
public class OpenApiLoader {
41+
42+
private Application application;
43+
44+
public OpenApiLoader(Application application) {
45+
this.application = application;
46+
}
47+
48+
public OpenAPI load(List<String> resourcePackages, List<String> resourceClasses, URL specLocation, URL overrideSpecLocation) {
49+
50+
// override order
51+
// 1. class annotations
52+
// 2. spec (overrides annotations)
53+
// 3. override spec (overrides spec and annotations)
54+
55+
OpenAPI empty = new OpenAPI();
56+
57+
OpenAPI specFromAnnotations = !resourcePackages.isEmpty() || !resourceClasses.isEmpty()
58+
? loadSpecFromAnnotations(empty, resourcePackages, resourceClasses) : empty;
59+
OpenAPI spec = specLocation != null ? OpenApiMerger.merge(specFromAnnotations, loadSpec(specLocation)) : specFromAnnotations;
60+
OpenAPI specOverride = overrideSpecLocation != null ? OpenApiMerger.merge(spec, loadSpec(overrideSpecLocation)) : spec;
61+
62+
// sort paths for stable specs... OpenAPI loads them in different order depending on the JVM version
63+
return sortPaths(specOverride);
64+
}
65+
66+
protected OpenAPI loadSpecFromAnnotations(OpenAPI mergeInto, List<String> resourcePackages, List<String> resourceClasses) {
67+
68+
SwaggerConfiguration config = new SwaggerConfiguration();
69+
config.setOpenAPI(mergeInto);
70+
71+
if (!resourcePackages.isEmpty()) {
72+
config.setResourcePackages(new HashSet<>(resourcePackages));
73+
}
74+
75+
if (!resourceClasses.isEmpty()) {
76+
config.setResourceClasses(new HashSet<>(resourceClasses));
77+
}
78+
79+
JaxrsAnnotationScanner scanner = new JaxrsAnnotationScanner();
80+
scanner.setConfiguration(config);
81+
scanner.setApplication(application);
82+
83+
Reader reader = new Reader();
84+
reader.setConfiguration(config);
85+
reader.setApplication(application);
86+
return reader.read(scanner.classes(), scanner.resources());
87+
}
88+
89+
protected OpenAPI sortPaths(OpenAPI api) {
90+
91+
Paths paths = api.getPaths();
92+
if (paths == null) {
93+
return api;
94+
}
95+
96+
String[] keys = paths.keySet().toArray(new String[0]);
97+
Arrays.sort(keys);
98+
99+
Paths sorted = new Paths();
100+
for (String key : keys) {
101+
sorted.put(key, paths.get(key));
102+
}
103+
104+
api.setPaths(sorted);
105+
106+
return api;
107+
}
108+
109+
protected OpenAPI loadSpec(URL location) {
110+
111+
ObjectMapper mapper = createMapper(location);
112+
try {
113+
return mapper.readValue(location, OpenAPI.class);
114+
} catch (IOException e) {
115+
throw new RuntimeException("Error reading configuration from " + location, e);
116+
}
117+
}
118+
119+
protected ObjectMapper createMapper(URL location) {
120+
return location.getFile().toLowerCase().endsWith(".json")
121+
? Json.mapper()
122+
: Yaml.mapper();
123+
}
124+
}

0 commit comments

Comments
 (0)