Skip to content

Commit 213564a

Browse files
#18388: Add Mutiny support to JaxRS (#18389)
* #18388: Add Mutiny support to JaxRS * Updated samples * Updated doccs * Updated example to 3_0 * Updated sample
1 parent 7b0f963 commit 213564a

File tree

89 files changed

+15217
-2
lines changed

Some content is hidden

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

89 files changed

+15217
-2
lines changed
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
generatorName: jaxrs-spec
2+
outputDir: samples/server/petstore/jaxrs-spec-quarkus-mutiny
3+
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
4+
templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec
5+
additionalProperties:
6+
artifactId: jaxrs-spec-petstore-server
7+
serializableModel: "true"
8+
hideGenerationTimestamp: "true"
9+
implicitHeadersRegex: (api_key|enum_header_string)
10+
generateBuilders: "true"
11+
useMicroProfileOpenAPIAnnotations: "true"
12+
useAsync: "true"
13+
useMutiny: "true"
14+
library: "quarkus"
15+
dateLibrary: "java8-localdatetime"

docs/generators/jaxrs-cxf-cdi.md

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
7878
|useBeanValidation|Use BeanValidation API annotations| |true|
7979
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
8080
|useMicroProfileOpenAPIAnnotations|Whether to generate Microprofile OpenAPI annotations. Only valid when library is set to quarkus.| |false|
81+
|useMutiny|Whether to use Smallrye Mutiny instead of CompletionStage for asynchronous computation. Only valid when library is set to quarkus.| |false|
8182
|useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |false|
8283
|useSwaggerAnnotations|Whether to generate Swagger annotations.| |true|
8384
|useTags|use tags for creating interface and controller classnames| |false|

docs/generators/jaxrs-spec.md

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
7878
|useBeanValidation|Use BeanValidation API annotations| |true|
7979
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
8080
|useMicroProfileOpenAPIAnnotations|Whether to generate Microprofile OpenAPI annotations. Only valid when library is set to quarkus.| |false|
81+
|useMutiny|Whether to use Smallrye Mutiny instead of CompletionStage for asynchronous computation. Only valid when library is set to quarkus.| |false|
8182
|useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |false|
8283
|useSwaggerAnnotations|Whether to generate Swagger annotations.| |true|
8384
|useTags|use tags for creating interface and controller classnames| |false|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java

+9
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen {
3838
public static final String GENERATE_POM = "generatePom";
3939
public static final String USE_SWAGGER_ANNOTATIONS = "useSwaggerAnnotations";
4040
public static final String USE_MICROPROFILE_OPENAPI_ANNOTATIONS = "useMicroProfileOpenAPIAnnotations";
41+
public static final String USE_MUTINY = "useMutiny";
4142
public static final String OPEN_API_SPEC_FILE_LOCATION = "openApiSpecFileLocation";
4243
public static final String GENERATE_BUILDERS = "generateBuilders";
4344

@@ -53,6 +54,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen {
5354
private boolean generateBuilders = false;
5455
private boolean useSwaggerAnnotations = true;
5556
private boolean useMicroProfileOpenAPIAnnotations = false;
57+
private boolean useMutiny = false;
5658

5759
protected boolean useGzipFeature = false;
5860
private boolean useJackson = false;
@@ -120,6 +122,7 @@ public JavaJAXRSSpecServerCodegen() {
120122
cliOptions.add(CliOption.newBoolean(USE_MICROPROFILE_OPENAPI_ANNOTATIONS, "Whether to generate Microprofile OpenAPI annotations. Only valid when library is set to quarkus.", useMicroProfileOpenAPIAnnotations));
121123
cliOptions.add(CliOption.newString(OPEN_API_SPEC_FILE_LOCATION, "Location where the file containing the spec will be generated in the output folder. No file generated when set to null or empty string."));
122124
cliOptions.add(CliOption.newBoolean(SUPPORT_ASYNC, "Wrap responses in CompletionStage type, allowing asynchronous computation (requires JAX-RS 2.1).", supportAsync));
125+
cliOptions.add(CliOption.newBoolean(USE_MUTINY, "Whether to use Smallrye Mutiny instead of CompletionStage for asynchronous computation. Only valid when library is set to quarkus.", useMutiny));
123126
}
124127

125128
@Override
@@ -167,6 +170,12 @@ public void processOpts() {
167170
writePropertyBack(USE_MICROPROFILE_OPENAPI_ANNOTATIONS, useMicroProfileOpenAPIAnnotations);
168171
}
169172

173+
if (QUARKUS_LIBRARY.equals(library)) {
174+
if (additionalProperties.containsKey(USE_MUTINY)) {
175+
useMutiny = Boolean.parseBoolean(additionalProperties.get(USE_MUTINY).toString());
176+
}
177+
writePropertyBack(USE_MUTINY, useMutiny);
178+
}
170179

171180
if (additionalProperties.containsKey(GENERATE_BUILDERS)) {
172181
generateBuilders = Boolean.parseBoolean(additionalProperties.get(GENERATE_BUILDERS).toString());

modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/api.mustache

+5
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ import io.swagger.annotations.*;
1515
{{/useSwaggerAnnotations}}
1616

1717
{{#supportAsync}}
18+
{{#useMutiny}}
19+
import io.smallrye.mutiny.Uni;
20+
{{/useMutiny}}
21+
{{^useMutiny}}
1822
import java.util.concurrent.CompletionStage;
1923
import java.util.concurrent.CompletableFuture;
24+
{{/useMutiny}}
2025
{{/supportAsync}}
2126

2227
import java.io.InputStream;

modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/apiMethod.mustache

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@
4040
{{^vendorExtensions.x-java-is-response-void}}@org.eclipse.microprofile.openapi.annotations.media.Content(schema = @org.eclipse.microprofile.openapi.annotations.media.Schema(implementation = {{{baseType}}}.class{{#vendorExtensions.x-microprofile-open-api-return-schema-container}}, type = {{{.}}} {{/vendorExtensions.x-microprofile-open-api-return-schema-container}}{{#vendorExtensions.x-microprofile-open-api-return-unique-items}}, uniqueItems = true {{/vendorExtensions.x-microprofile-open-api-return-unique-items}})){{/vendorExtensions.x-java-is-response-void}}
4141
}){{^-last}},{{/-last}}{{/responses}}
4242
}){{/hasProduces}}{{/useMicroProfileOpenAPIAnnotations}}
43-
public {{#supportAsync}}CompletionStage<{{/supportAsync}}Response{{#supportAsync}}>{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}) {
44-
return {{#supportAsync}}CompletableFuture.supplyAsync(() -> {{/supportAsync}}Response.ok().entity("magic!").build(){{#supportAsync}}){{/supportAsync}};
43+
public {{#supportAsync}}{{#useMutiny}}Uni{{/useMutiny}}{{^useMutiny}}CompletionStage{{/useMutiny}}<{{/supportAsync}}Response{{#supportAsync}}>{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}) {
44+
return {{#supportAsync}}{{#useMutiny}}Uni.createFrom().item({{/useMutiny}}{{^useMutiny}}CompletableFuture.supplyAsync(() -> {{/useMutiny}}{{/supportAsync}}Response.ok().entity("magic!").build(){{#supportAsync}}){{/supportAsync}};
4545
}

modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/pom.mustache

+11
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
{{#useSwaggerAnnotations}}
4545
<io.swagger.annotations.version>1.6.10</io.swagger.annotations.version>
4646
{{/useSwaggerAnnotations}}
47+
{{#useMutiny}}
48+
<smallrye.rest.client.version>1.2.1</smallrye.rest.client.version>
49+
{{/useMutiny}}
4750
</properties>
4851
<dependencyManagement>
4952
<dependencies>
@@ -109,6 +112,14 @@
109112
<scope>provided</scope>
110113
</dependency>
111114
{{/useSwaggerAnnotations}}
115+
{{#useMutiny}}
116+
<dependency>
117+
<groupId>io.smallrye</groupId>
118+
<artifactId>smallrye-rest-client</artifactId>
119+
<version>${smallrye.rest.client.version}</version>
120+
<scope>test</scope>
121+
</dependency>
122+
{{/useMutiny}}
112123
</dependencies>
113124
<build>
114125
<plugins>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{#useMutiny}}Uni{{/useMutiny}}{{^useMutiny}}CompletionStage{{/useMutiny}}<{{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{#returnContainer}}{{#isMap}}Map<String, {{{returnBaseType}}}>{{/isMap}}{{#isArray}}{{{returnContainer}}}<{{{returnBaseType}}}>{{/isArray}}{{/returnContainer}}{{^returnContainer}}{{{returnBaseType}}}{{/returnContainer}}{{/returnResponse}}>

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java

+97
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,103 @@ public void generateApiForQuarkusWithGzipFeature() throws Exception {
808808
);
809809
}
810810

811+
@Test
812+
public void generateApiForQuarkusWithoutMutiny() throws Exception {
813+
final File output = Files.createTempDirectory("test").toFile();
814+
output.deleteOnExit();
815+
816+
final OpenAPI openAPI = new OpenAPIParser()
817+
.readLocation("src/test/resources/3_0/issue_4832.yaml", null, new ParseOptions()).getOpenAPI();
818+
819+
codegen.setOutputDir(output.getAbsolutePath());
820+
codegen.setLibrary(QUARKUS_LIBRARY);
821+
codegen.additionalProperties().put(SUPPORT_ASYNC, true);
822+
codegen.additionalProperties().put(USE_TAGS, true); //And use tags to generate everything in PingApi.java
823+
824+
final ClientOptInput input = new ClientOptInput()
825+
.openAPI(openAPI)
826+
.config(codegen); //Using JavaJAXRSSpecServerCodegen
827+
828+
final DefaultGenerator generator = new DefaultGenerator();
829+
final List<File> files = generator.opts(input).generate(); //When generating files
830+
831+
//Then the java files are compilable
832+
validateJavaSourceFiles(files);
833+
834+
//And the generated class contains CompletionStage<Response>
835+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/PingApi.java");
836+
TestUtils.assertFileContains(output.toPath().resolve("src/gen/java/org/openapitools/api/PingApi.java"),
837+
"CompletionStage<Response> pingGetBoolean", //Support primitive types response
838+
"CompletionStage<Response> pingGetInteger" //Support primitive types response
839+
);
840+
}
841+
842+
@Test
843+
public void generateApiForQuarkusWithMutinyApi() throws Exception {
844+
final File output = Files.createTempDirectory("test").toFile();
845+
output.deleteOnExit();
846+
847+
final OpenAPI openAPI = new OpenAPIParser()
848+
.readLocation("src/test/resources/3_0/issue_4832.yaml", null, new ParseOptions()).getOpenAPI();
849+
850+
codegen.setOutputDir(output.getAbsolutePath());
851+
codegen.setLibrary(QUARKUS_LIBRARY);
852+
codegen.additionalProperties().put(USE_TAGS, true); //And use tags to generate everything in PingApi.java
853+
codegen.additionalProperties().put(SUPPORT_ASYNC, true);
854+
codegen.additionalProperties().put(INTERFACE_ONLY, true);
855+
codegen.additionalProperties().put(USE_MUTINY, true);
856+
857+
final ClientOptInput input = new ClientOptInput()
858+
.openAPI(openAPI)
859+
.config(codegen); //Using JavaJAXRSSpecServerCodegen
860+
861+
final DefaultGenerator generator = new DefaultGenerator();
862+
final List<File> files = generator.opts(input).generate(); //When generating files
863+
864+
//Then the java files are compilable
865+
validateJavaSourceFiles(files);
866+
867+
//And the generated class contains CompletionStage<Response>
868+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/PingApi.java");
869+
TestUtils.assertFileContains(output.toPath().resolve("src/gen/java/org/openapitools/api/PingApi.java"),
870+
"Uni<Boolean> pingGetBoolean", //Support primitive types response
871+
"Uni<Integer> pingGetInteger" //Support primitive types response
872+
);
873+
}
874+
875+
876+
@Test
877+
public void generateApiForQuarkusWithMutinyImpl() throws Exception {
878+
final File output = Files.createTempDirectory("test").toFile();
879+
output.deleteOnExit();
880+
881+
final OpenAPI openAPI = new OpenAPIParser()
882+
.readLocation("src/test/resources/3_0/issue_4832.yaml", null, new ParseOptions()).getOpenAPI();
883+
884+
codegen.setOutputDir(output.getAbsolutePath());
885+
codegen.setLibrary(QUARKUS_LIBRARY);
886+
codegen.additionalProperties().put(USE_TAGS, true); //And use tags to generate everything in PingApi.java
887+
codegen.additionalProperties().put(SUPPORT_ASYNC, true);
888+
codegen.additionalProperties().put(USE_MUTINY, true);
889+
890+
final ClientOptInput input = new ClientOptInput()
891+
.openAPI(openAPI)
892+
.config(codegen); //Using JavaJAXRSSpecServerCodegen
893+
894+
final DefaultGenerator generator = new DefaultGenerator();
895+
final List<File> files = generator.opts(input).generate(); //When generating files
896+
897+
//Then the java files are compilable
898+
validateJavaSourceFiles(files);
899+
900+
//And the generated class contains CompletionStage<Response>
901+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/PingApi.java");
902+
TestUtils.assertFileContains(output.toPath().resolve("src/gen/java/org/openapitools/api/PingApi.java"),
903+
"Uni<Response> pingGetBoolean", //Support primitive types response
904+
"Uni<Response> pingGetInteger" //Support primitive types response
905+
);
906+
}
907+
811908
@Test
812909
public void testHandleRequiredAndReadOnlyPropertiesCorrectly() throws Exception {
813910
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*
2+
!target/*-runner
3+
!target/*-runner.jar
4+
!target/lib/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# OpenAPI Generator Ignore
2+
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
3+
4+
# Use this file to prevent files from being overwritten by the generator.
5+
# The patterns follow closely to .gitignore or .dockerignore.
6+
7+
# As an example, the C# client generator defines ApiClient.cs.
8+
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
9+
#ApiClient.cs
10+
11+
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+
#foo/*/qux
13+
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+
#foo/**/qux
17+
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+
# You can also negate patterns with an exclamation (!).
20+
# For example, you can ignore all files in a docs folder with the file extension .md:
21+
#docs/*.md
22+
# Then explicitly reverse the ignore rule for a single file:
23+
#!docs/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
.dockerignore
2+
README.md
3+
pom.xml
4+
src/gen/java/org/openapitools/api/AnotherFakeApi.java
5+
src/gen/java/org/openapitools/api/FakeApi.java
6+
src/gen/java/org/openapitools/api/FakeClassnameTestApi.java
7+
src/gen/java/org/openapitools/api/FooApi.java
8+
src/gen/java/org/openapitools/api/PetApi.java
9+
src/gen/java/org/openapitools/api/RestApplication.java
10+
src/gen/java/org/openapitools/api/RestResourceRoot.java
11+
src/gen/java/org/openapitools/api/StoreApi.java
12+
src/gen/java/org/openapitools/api/UserApi.java
13+
src/gen/java/org/openapitools/model/AdditionalPropertiesClass.java
14+
src/gen/java/org/openapitools/model/AllOfWithSingleRef.java
15+
src/gen/java/org/openapitools/model/Animal.java
16+
src/gen/java/org/openapitools/model/ArrayOfArrayOfNumberOnly.java
17+
src/gen/java/org/openapitools/model/ArrayOfNumberOnly.java
18+
src/gen/java/org/openapitools/model/ArrayTest.java
19+
src/gen/java/org/openapitools/model/Capitalization.java
20+
src/gen/java/org/openapitools/model/Cat.java
21+
src/gen/java/org/openapitools/model/Category.java
22+
src/gen/java/org/openapitools/model/ChildWithNullable.java
23+
src/gen/java/org/openapitools/model/ClassModel.java
24+
src/gen/java/org/openapitools/model/Client.java
25+
src/gen/java/org/openapitools/model/DeprecatedObject.java
26+
src/gen/java/org/openapitools/model/Dog.java
27+
src/gen/java/org/openapitools/model/EnumArrays.java
28+
src/gen/java/org/openapitools/model/EnumClass.java
29+
src/gen/java/org/openapitools/model/EnumTest.java
30+
src/gen/java/org/openapitools/model/FakeBigDecimalMap200Response.java
31+
src/gen/java/org/openapitools/model/FileSchemaTestClass.java
32+
src/gen/java/org/openapitools/model/Foo.java
33+
src/gen/java/org/openapitools/model/FooGetDefaultResponse.java
34+
src/gen/java/org/openapitools/model/FormatTest.java
35+
src/gen/java/org/openapitools/model/HasOnlyReadOnly.java
36+
src/gen/java/org/openapitools/model/HealthCheckResult.java
37+
src/gen/java/org/openapitools/model/MapTest.java
38+
src/gen/java/org/openapitools/model/MixedPropertiesAndAdditionalPropertiesClass.java
39+
src/gen/java/org/openapitools/model/Model200Response.java
40+
src/gen/java/org/openapitools/model/ModelApiResponse.java
41+
src/gen/java/org/openapitools/model/ModelFile.java
42+
src/gen/java/org/openapitools/model/ModelList.java
43+
src/gen/java/org/openapitools/model/ModelReturn.java
44+
src/gen/java/org/openapitools/model/Name.java
45+
src/gen/java/org/openapitools/model/NullableClass.java
46+
src/gen/java/org/openapitools/model/NumberOnly.java
47+
src/gen/java/org/openapitools/model/ObjectWithDeprecatedFields.java
48+
src/gen/java/org/openapitools/model/Order.java
49+
src/gen/java/org/openapitools/model/OuterComposite.java
50+
src/gen/java/org/openapitools/model/OuterEnum.java
51+
src/gen/java/org/openapitools/model/OuterEnumDefaultValue.java
52+
src/gen/java/org/openapitools/model/OuterEnumInteger.java
53+
src/gen/java/org/openapitools/model/OuterEnumIntegerDefaultValue.java
54+
src/gen/java/org/openapitools/model/OuterObjectWithEnumProperty.java
55+
src/gen/java/org/openapitools/model/ParentWithNullable.java
56+
src/gen/java/org/openapitools/model/Pet.java
57+
src/gen/java/org/openapitools/model/ReadOnlyFirst.java
58+
src/gen/java/org/openapitools/model/SingleRefType.java
59+
src/gen/java/org/openapitools/model/SpecialModelName.java
60+
src/gen/java/org/openapitools/model/Tag.java
61+
src/gen/java/org/openapitools/model/TestInlineFreeformAdditionalPropertiesRequest.java
62+
src/gen/java/org/openapitools/model/User.java
63+
src/main/docker/Dockerfile.jvm
64+
src/main/docker/Dockerfile.native
65+
src/main/resources/META-INF/openapi.yaml
66+
src/main/resources/application.properties
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
7.5.0-SNAPSHOT
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# JAX-RS server with OpenAPI using Quarkus
2+
3+
## Overview
4+
This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using an
5+
[OpenAPI-Spec](https://openapis.org), you can easily generate a server stub.
6+
7+
This is an example of building a OpenAPI-enabled JAX-RS server.
8+
This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework and
9+
the [Eclipse-MicroProfile-OpenAPI](https://github.com/eclipse/microprofile-open-api) addition.
10+
11+
The pom file is configured to use [Quarkus](https://quarkus.io/) as application server.
12+
13+
14+
To start the server in dev mode, run this maven command:
15+
16+
```bash
17+
mvn compile quarkus:dev
18+
```
19+
20+
You can then call your server endpoints under:
21+
22+
```
23+
http://localhost:8080/
24+
```
25+
26+
In dev-mode, you can open Swagger-UI at:
27+
28+
```
29+
http://localhost:8080/swagger-ui/
30+
```
31+
32+
Read more in the [Quarkus OpenAPI guide](https://quarkus.io/guides/openapi-swaggerui-guide).
33+

0 commit comments

Comments
 (0)