Skip to content

Commit 8e82238

Browse files
committed
[feat][jaxrs-cxf-client] add optional generation of oas3 annotations
1 parent b4378a6 commit 8e82238

5 files changed

Lines changed: 270 additions & 4 deletions

File tree

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,17 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen
4747

4848
public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles";
4949

50+
public static final String OAS3 = "oas3";
51+
5052
@Getter protected boolean useGenericResponse = false;
5153

5254
@Getter protected boolean useGzipFeatureForTests = false;
5355

5456
@Getter protected boolean useLoggingFeatureForTests = false;
5557

5658
@Setter protected boolean useAbstractionForFiles = false;
59+
60+
@Setter protected boolean oas3 = false;
5761

5862
public JavaCXFClientCodegen() {
5963
super();
@@ -93,6 +97,7 @@ public JavaCXFClientCodegen() {
9397
cliOptions.add(CliOption.newBoolean(USE_LOGGING_FEATURE_FOR_TESTS, "Use Logging Feature for tests"));
9498
cliOptions.add(CliOption.newBoolean(USE_GENERIC_RESPONSE, "Use generic response"));
9599
cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk."));
100+
cliOptions.add(CliOption.newBoolean(OAS3, "Generate Swagger annotations in version 3 instead of version 2."));
96101
}
97102

98103
@Override
@@ -103,6 +108,7 @@ public void processOpts() {
103108
convertPropertyToBooleanAndWriteBack(USE_LOGGING_FEATURE_FOR_TESTS, this::setUseLoggingFeatureForTests);
104109
convertPropertyToBooleanAndWriteBack(JACKSON, this::setJackson);
105110
convertPropertyToBooleanAndWriteBack(USE_ABSTRACTION_FOR_FILES, this::setUseAbstractionForFiles);
111+
convertPropertyToBooleanAndWriteBack(OAS3, this::setOas3);
106112

107113
supportingFiles.clear(); // Don't need extra files provided by AbstractJAX-RS & Java Codegen
108114

@@ -132,6 +138,13 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
132138
super.postProcessModelProperty(model, property);
133139
model.imports.remove("ApiModelProperty");
134140
model.imports.remove("ApiModel");
141+
142+
if (oas3) {
143+
apiTemplateFiles.remove("api.mustache");
144+
importMapping.remove("ApiModelProperty");
145+
importMapping.remove("ApiModel");
146+
apiTemplateFiles.put("api_oas3.mustache", ".java");
147+
}
135148

136149
if (jackson) {
137150
//Add jackson imports when model has inner enum
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package {{package}};
2+
3+
{{#imports}}import {{import}};
4+
{{/imports}}
5+
6+
import java.io.InputStream;
7+
import java.io.OutputStream;
8+
import java.util.List;
9+
import java.util.Map;
10+
import {{javaxPackage}}.ws.rs.*;
11+
import {{javaxPackage}}.ws.rs.core.Response;
12+
import {{javaxPackage}}.ws.rs.core.MediaType;
13+
import org.apache.cxf.jaxrs.ext.multipart.*;
14+
15+
import io.swagger.v3.oas.annotations.Operation;
16+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
17+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
18+
import io.swagger.v3.oas.annotations.media.ArraySchema;
19+
import io.swagger.v3.oas.annotations.media.Content;
20+
import io.swagger.v3.oas.annotations.media.Schema;
21+
{{#useBeanValidation}}
22+
import {{javaxPackage}}.validation.constraints.*;
23+
import {{javaxPackage}}.validation.Valid;
24+
{{/useBeanValidation}}
25+
26+
{{#appName}}
27+
/**
28+
* {{{appName}}}
29+
*
30+
{{#appDescription}}
31+
* <p>{{{.}}}
32+
*
33+
{{/appDescription}}
34+
*/
35+
{{/appName}}
36+
@Path("{{#useAnnotatedBasePath}}{{contextPath}}{{/useAnnotatedBasePath}}{{commonPath}}")
37+
{{#addConsumesProducesJson}}
38+
@Consumes(MediaType.APPLICATION_JSON)
39+
@Produces(MediaType.APPLICATION_JSON)
40+
{{/addConsumesProducesJson}}
41+
public interface {{classname}} {
42+
{{#operations}}
43+
{{#operation}}
44+
45+
{{#summary}}
46+
/**
47+
* {{summary}}
48+
*
49+
{{#notes}}
50+
* {{.}}
51+
*
52+
{{/notes}}
53+
*/
54+
{{/summary}}
55+
@{{httpMethod}}
56+
{{#subresourceOperation}}@Path("{{{path}}}"){{/subresourceOperation}}
57+
{{#hasConsumes}}
58+
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} })
59+
{{/hasConsumes}}
60+
{{#hasProduces}}
61+
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} })
62+
{{/hasProduces}}
63+
@Operation(summary = "{{{summary}}}", tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{^-last}}, {{/-last}}{{/vendorExtensions.x-tags}} })
64+
{{#implicitHeadersParams.0}}
65+
@io.swagger.annotations.ApiImplicitParams({
66+
{{#implicitHeadersParams}}
67+
@io.swagger.annotations.ApiImplicitParam(name = "{{{baseName}}}", value = "{{{description}}}", {{#required}}required = true,{{/required}} dataType = "{{{dataType}}}", paramType = "header"){{^-last}},{{/-last}}
68+
{{/implicitHeadersParams}}
69+
})
70+
{{/implicitHeadersParams.0}}
71+
@ApiResponses(value = { {{#responses}}
72+
@ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}", content = @Content(mediaType = {{#content}}{{#entrySet}}"{{{key}}}"{{/entrySet}}{{/content}}{{^content}}"*/*"{{/content}}, {{#containerType}}array = @ArraySchema({{/containerType}}schema = @Schema(implementation = {{#isFile}}{{#useAbstractionForFiles}}InputStream{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{baseType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{baseType}}}{{/isFile}}.class){{#containerType}}){{/containerType}})){{^-last}},{{/-last}}{{/responses}} })
73+
public {{>returnTypes}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}});
74+
{{/operation}}
75+
}
76+
{{/operations}}

modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/pojo.mustache

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
{{#oas3}}
2+
import io.swagger.v3.oas.annotations.media.Schema;
3+
{{/oas3}}
4+
{{^oas3}}
15
import io.swagger.annotations.ApiModelProperty;
6+
{{/oas3}}
27
import java.util.Objects;
38
{{#withXml}}
49
import {{javaxPackage}}.xml.bind.annotation.XmlElement;
@@ -13,9 +18,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
1318

1419
{{#description}}
1520
/**
16-
* {{{description}}}
21+
* {{{.}}}
1722
**/
18-
@ApiModel(description="{{{description}}}")
23+
{{^oas3}}@ApiModel(description="{{{.}}}"){{/oas3}}
1924
{{/description}}
2025
{{>additionalModelTypeAnnotations}}{{>xmlPojoAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}
2126
{{#vendorExtensions.x-class-extra-annotation}}
@@ -28,8 +33,13 @@ public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}}{{#vendorExtensi
2833
{{#withXml}}
2934
@XmlElement(name="{{baseName}}"{{#required}}, required = {{required}}{{/required}})
3035
{{/withXml}}
31-
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{#useBeanValidation}}
32-
@Valid{{/useBeanValidation}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}
36+
{{#oas3}}
37+
@Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}")
38+
{{/oas3}}
39+
{{^oas3}}
40+
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}")
41+
{{/oas3}}
42+
{{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{#useBeanValidation}}@Valid{{/useBeanValidation}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}
3343
{{#description}}
3444
/**
3545
* {{{.}}}

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,59 @@ public void testUseAbstractionForFiles() throws Exception {
336336
"public FilesUploadPost200Response filesUploadPost(InputStream body);"
337337
);
338338
}
339+
340+
@Test
341+
public void testUseOas3Imports() throws Exception {
342+
343+
Map<String, Object> properties = new HashMap<>();
344+
properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api");
345+
properties.put(CodegenConstants.MODEL_PACKAGE, "xyz.abcdef.api");
346+
347+
properties.put(JavaCXFClientCodegen.OAS3, true);
348+
349+
File output = Files.createTempDirectory("test").toFile();
350+
output.deleteOnExit();
351+
352+
final CodegenConfigurator configurator = new CodegenConfigurator()
353+
.setGeneratorName("jaxrs-cxf-client")
354+
.setAdditionalProperties(properties)
355+
.setInputSpec("src/test/resources/3_1/java/issue_19907.yaml")
356+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
357+
358+
359+
DefaultGenerator generator = new DefaultGenerator();
360+
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
361+
files.forEach(File::deleteOnExit);
362+
363+
validateJavaSourceFiles(files);
364+
365+
Path petApi = Paths.get(output + "/src/gen/java/xyz/abcdef/api/PetApi.java");
366+
Path petModel = Paths.get(output + "/src/gen/java/xyz/abcdef/api/Pet.java");
367+
368+
TestUtils.assertFileContains(petApi,
369+
// imports
370+
"import io.swagger.v3.oas.annotations.responses.ApiResponses;",
371+
"import io.swagger.v3.oas.annotations.responses.ApiResponse;",
372+
"import io.swagger.v3.oas.annotations.media.ArraySchema;",
373+
"import io.swagger.v3.oas.annotations.media.Content;",
374+
375+
"@Path(\"/pet/{petId}\")",
376+
"@Produces({ \"application/json\" })",
377+
"@Operation(summary = \"Find pet by ID\", tags={ })",
378+
"@ApiResponse(responseCode = \"200\", description = \"successful operation\", content = @Content(mediaType = \"application/json\", schema = @Schema(implementation = Pet.class))),",
379+
"@ApiResponse(responseCode = \"400\", description = \"Invalid ID supplied\", content = @Content(mediaType = \"*/*\", schema = @Schema(implementation = Void.class))),",
380+
"@ApiResponse(responseCode = \"404\", description = \"Pet not found\", content = @Content(mediaType = \"*/*\", schema = @Schema(implementation = Void.class))) })",
381+
"public Pet getPetById(@PathParam(\"petId\") Long petId);"
382+
383+
);
384+
385+
TestUtils.assertFileNotContains(petModel,
386+
"import io.swagger.annotations.ApiModel;",
387+
"@ApiModel(description=\"A pet for sale in the pet store\")"
388+
);
389+
390+
TestUtils.assertFileContains(petModel,
391+
"@Schema(description = \"\")"
392+
);
393+
}
339394
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
openapi: 3.1.0
2+
servers:
3+
- url: 'http://petstore.swagger.io/v2'
4+
info:
5+
description: >-
6+
This is a sample server Petstore server. For this sample, you can use the api key
7+
`special-key` to test the authorization filters.
8+
version: 1.0.0
9+
title: OpenAPI Petstore
10+
license:
11+
name: Apache-2.0
12+
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
13+
paths:
14+
'/pet/{petId}':
15+
get:
16+
tags:
17+
- pet
18+
summary: Find pet by ID
19+
description: Returns a single pet
20+
operationId: getPetById
21+
parameters:
22+
- name: petId
23+
in: path
24+
description: ID of pet to return
25+
required: true
26+
schema:
27+
type: integer
28+
format: int64
29+
responses:
30+
'200':
31+
description: successful operation
32+
content:
33+
application/json:
34+
schema:
35+
$ref: '#/components/schemas/Pet'
36+
'400':
37+
description: Invalid ID supplied
38+
'404':
39+
description: Pet not found
40+
components:
41+
schemas:
42+
Tag:
43+
title: Pet Tag
44+
description: A tag for a pet
45+
type: object
46+
properties:
47+
id:
48+
type: integer
49+
format: int64
50+
name:
51+
type: string
52+
Pet:
53+
title: a Pet
54+
description: A pet for sale in the pet store
55+
type: object
56+
properties:
57+
tags:
58+
type: array
59+
items:
60+
$ref: '#/components/schemas/Tag'
61+
tagsDefaultList:
62+
type: array
63+
default: []
64+
items:
65+
$ref: '#/components/schemas/Tag'
66+
tagsUnique:
67+
type: array
68+
uniqueItems: true
69+
items:
70+
$ref: '#/components/schemas/Tag'
71+
tagsDefaultSet:
72+
type: array
73+
default: [ ]
74+
uniqueItems: true
75+
items:
76+
$ref: '#/components/schemas/Tag'
77+
stringList:
78+
type: array
79+
items:
80+
type: string
81+
stringDefaultList:
82+
type: array
83+
default:
84+
- A
85+
- B
86+
items:
87+
type: string
88+
stringEmptyDefaultList:
89+
type: array
90+
default: []
91+
items:
92+
type: string
93+
stringSet:
94+
type: array
95+
uniqueItems: true
96+
items:
97+
type: string
98+
stringDefaultSet:
99+
type: array
100+
uniqueItems: true
101+
default:
102+
- A
103+
- B
104+
items:
105+
type: string
106+
stringEmptyDefaultSet:
107+
type: array
108+
uniqueItems: true
109+
default: []
110+
items:
111+
type: string
112+

0 commit comments

Comments
 (0)