Skip to content

Commit 854bd89

Browse files
shybovychaArtem Shubovychwing328
authored andcommitted
[enhancement] [jaxrs-spec] Add builders to models (OpenAPITools#4930)
* Update formatting in jaxrs-spec POJOs * Add generateBuilders option * Update formatting in jaxrs-spec POJOs * Disable the builders generation by default * Ensure samples are up-to-date * Revert newline change * Run ensure-up-to-date * update doc * fix merge conflicts Co-authored-by: Artem Shubovych <ashubovych@atlassian.com> Co-authored-by: William Cheng <wing328hk@gmail.com>
1 parent be3e13e commit 854bd89

File tree

150 files changed

+4731
-1307
lines changed

Some content is hidden

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

150 files changed

+4731
-1307
lines changed

docs/generators/jaxrs-cxf-cdi.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ sidebar_label: jaxrs-cxf-cdi
2222
|disableHtmlEscaping|Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)| |false|
2323
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
2424
|fullJavaUtil|whether to use fully qualified name for classes under java.util. This option only works for Java API client| |false|
25+
|generateBuilders|Whether to generate builders for models.| |false|
2526
|generatePom|Whether to generate pom.xml if the file does not already exist.| |true|
2627
|groupId|groupId in generated pom.xml| |org.openapitools|
2728
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |false|

docs/generators/jaxrs-spec.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ sidebar_label: jaxrs-spec
2222
|disableHtmlEscaping|Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)| |false|
2323
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
2424
|fullJavaUtil|whether to use fully qualified name for classes under java.util. This option only works for Java API client| |false|
25+
|generateBuilders|Whether to generate builders for models.| |false|
2526
|generatePom|Whether to generate pom.xml if the file does not already exist.| |true|
2627
|groupId|groupId in generated pom.xml| |org.openapitools|
2728
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |false|

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

+10-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen {
3838
public static final String USE_SWAGGER_ANNOTATIONS = "useSwaggerAnnotations";
3939
public static final String JACKSON = "jackson";
4040
public static final String OPEN_API_SPEC_FILE_LOCATION = "openApiSpecFileLocation";
41+
public static final String GENERATE_BUILDERS = "generateBuilders";
4142

4243
public static final String QUARKUS_LIBRARY = "quarkus";
4344
public static final String THORNTAIL_LIBRARY = "thorntail";
@@ -47,6 +48,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen {
4748
private boolean interfaceOnly = false;
4849
private boolean returnResponse = false;
4950
private boolean generatePom = true;
51+
private boolean generateBuilders = false;
5052
private boolean useSwaggerAnnotations = true;
5153
private boolean useJackson = false;
5254
private String openApiSpecFileLocation = "src/main/openapi/openapi.yaml";
@@ -101,6 +103,7 @@ public JavaJAXRSSpecServerCodegen() {
101103

102104
cliOptions.add(library);
103105
cliOptions.add(CliOption.newBoolean(GENERATE_POM, "Whether to generate pom.xml if the file does not already exist.").defaultValue(String.valueOf(generatePom)));
106+
cliOptions.add(CliOption.newBoolean(GENERATE_BUILDERS, "Whether to generate builders for models.").defaultValue(String.valueOf(generateBuilders)));
104107
cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files.").defaultValue(String.valueOf(interfaceOnly)));
105108
cliOptions.add(CliOption.newBoolean(RETURN_RESPONSE, "Whether generate API interface should return javax.ws.rs.core.Response instead of a deserialized entity. Only useful if interfaceOnly is true.").defaultValue(String.valueOf(returnResponse)));
106109
cliOptions.add(CliOption.newBoolean(USE_SWAGGER_ANNOTATIONS, "Whether to generate Swagger annotations.", useSwaggerAnnotations));
@@ -124,14 +127,20 @@ public void processOpts() {
124127
additionalProperties.remove(RETURN_RESPONSE);
125128
}
126129
}
127-
if(QUARKUS_LIBRARY.equals(library) || THORNTAIL_LIBRARY.equals(library) || HELIDON_LIBRARY.equals(library) || OPEN_LIBERTY_LIBRARY.equals(library)) {
130+
if (QUARKUS_LIBRARY.equals(library) || THORNTAIL_LIBRARY.equals(library) || HELIDON_LIBRARY.equals(library) || OPEN_LIBERTY_LIBRARY.equals(library)) {
128131
useSwaggerAnnotations = false;
129132
} else {
130133
if (additionalProperties.containsKey(USE_SWAGGER_ANNOTATIONS)) {
131134
useSwaggerAnnotations = Boolean.valueOf(additionalProperties.get(USE_SWAGGER_ANNOTATIONS).toString());
132135
}
133136
}
134137
writePropertyBack(USE_SWAGGER_ANNOTATIONS, useSwaggerAnnotations);
138+
139+
if (additionalProperties.containsKey(GENERATE_BUILDERS)) {
140+
generateBuilders = Boolean.valueOf(additionalProperties.get(GENERATE_BUILDERS).toString());
141+
}
142+
additionalProperties.put(GENERATE_BUILDERS, generateBuilders);
143+
135144
if (additionalProperties.containsKey(OPEN_API_SPEC_FILE_LOCATION)) {
136145
openApiSpecFileLocation = additionalProperties.get(OPEN_API_SPEC_FILE_LOCATION).toString();
137146
} else if(QUARKUS_LIBRARY.equals(library) || THORNTAIL_LIBRARY.equals(library) || HELIDON_LIBRARY.equals(library)) {

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

+46-10
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@ import com.fasterxml.jackson.annotation.JsonProperty;
66
import com.fasterxml.jackson.annotation.JsonCreator;
77
import com.fasterxml.jackson.annotation.JsonValue;
88

9-
{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}
10-
/**
9+
{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/**
1110
* {{description}}
12-
**/{{/description}}{{#useSwaggerAnnotations}}
13-
{{#description}}{{>additionalModelTypeAnnotations}}@ApiModel(description = "{{{description}}}"){{/description}}{{/useSwaggerAnnotations}}
11+
**/{{/description}}
12+
{{#useSwaggerAnnotations}}{{#description}}{{>additionalModelTypeAnnotations}}@ApiModel(description = "{{{description}}}"){{/description}}{{/useSwaggerAnnotations}}
1413
{{>generatedAnnotation}}public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} {
1514
{{#vars}}{{#isEnum}}{{^isContainer}}
1615

1716
{{>enumClass}}{{/isContainer}}{{#isContainer}}{{#mostInnerItems}}
1817

1918
{{>enumClass}}{{/mostInnerItems}}{{/isContainer}}{{/isEnum}}
20-
private {{#useBeanValidation}}@Valid{{/useBeanValidation}} {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};{{/vars}}
19+
private {{#useBeanValidation}}@Valid {{/useBeanValidation}}{{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};{{/vars}}
2120

22-
{{#vars}}
23-
/**
21+
{{#vars}}/**
2422
{{#description}}
2523
* {{description}}
2624
{{/description}}
@@ -36,17 +34,22 @@ import com.fasterxml.jackson.annotation.JsonValue;
3634
return this;
3735
}
3836

37+
{{#generateBuilders}}public {{classname}}({{#vars}}{{{datatypeWithEnum}}} {{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}) {
38+
{{#vars}}
39+
this.{{name}} = {{name}};
40+
{{/vars}}
41+
}{{/generateBuilders}}
42+
3943
{{#vendorExtensions.x-extra-annotation}}{{{vendorExtensions.x-extra-annotation}}}{{/vendorExtensions.x-extra-annotation}}{{#useSwaggerAnnotations}}
4044
@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{/useSwaggerAnnotations}}
4145
@JsonProperty("{{baseName}}")
4246
{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{getter}}() {
4347
return {{name}};
4448
}
49+
4550
public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
4651
this.{{name}} = {{name}};
47-
}
48-
49-
{{/vars}}
52+
}{{/vars}}
5053

5154
@Override
5255
public boolean equals(java.lang.Object o) {
@@ -88,4 +91,37 @@ import com.fasterxml.jackson.annotation.JsonValue;
8891
}
8992
return o.toString().replace("\n", "\n ");
9093
}
94+
95+
{{#generateBuilders}}
96+
public static Builder builder() {
97+
return new Builder();
98+
}
99+
100+
public static class Builder {
101+
{{#vars}}
102+
private {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
103+
{{/vars}}
104+
105+
{{#vars}}
106+
/**
107+
{{#description}}
108+
* {{description}}
109+
{{/description}}
110+
{{#minimum}}
111+
* minimum: {{minimum}}
112+
{{/minimum}}
113+
{{#maximum}}
114+
* maximum: {{maximum}}
115+
{{/maximum}}
116+
**/
117+
public Builder {{name}}({{{datatypeWithEnum}}} {{name}}) {
118+
this.{{name}} = {{name}};
119+
return this;
120+
}
121+
{{/vars}}
122+
123+
public {{classname}} build() {
124+
return new {{classname}}({{#vars}}{{name}}{{#hasMore}}, {{/hasMore}}{{/vars}});
125+
}
126+
}{{/generateBuilders}}
91127
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.3.1-SNAPSHOT
1+
4.3.1-SNAPSHOT
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.3.0-SNAPSHOT
1+
4.2.3-SNAPSHOT

samples/server/petstore/jaxrs-spec-interface-response/src/gen/java/org/openapitools/api/AnotherFakeApi.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@
1313
import javax.validation.constraints.*;
1414
import javax.validation.Valid;
1515

16-
@Path("/another-fake")
17-
@Api(description = "the another-fake API")
16+
@Path("/AnotherFake")
17+
@Api(description = "the AnotherFake API")
1818
public interface AnotherFakeApi {
1919

2020
@PATCH
21-
@Path("/dummy")
2221
@Consumes({ "application/json" })
2322
@Produces({ "application/json" })
2423
@ApiOperation(value = "To test special tags", notes = "To test special tags and operation ID starting with number", tags={ "$another-fake?" })
2524
@ApiResponses(value = {
2625
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
27-
Response call123testSpecialTags(@Valid Client client);
26+
Response call123testSpecialTags(@Valid Client body);
2827
}

samples/server/petstore/jaxrs-spec-interface-response/src/gen/java/org/openapitools/api/FakeApi.java

+26-29
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import org.openapitools.model.FileSchemaTestClass;
88
import org.joda.time.LocalDate;
99
import java.util.Map;
10-
import org.openapitools.model.ModelApiResponse;
1110
import org.openapitools.model.OuterComposite;
1211
import org.openapitools.model.User;
12+
import org.openapitools.model.XmlItem;
1313

1414
import javax.ws.rs.*;
1515
import javax.ws.rs.core.Response;
@@ -22,65 +22,66 @@
2222
import javax.validation.constraints.*;
2323
import javax.validation.Valid;
2424

25-
@Path("/fake")
26-
@Api(description = "the fake API")
25+
@Path("/Fake")
26+
@Api(description = "the Fake API")
2727
public interface FakeApi {
2828

2929
@POST
30-
@Path("/outer/boolean")
30+
@Consumes({ "application/xml", "application/xml; charset=utf-8", "application/xml; charset=utf-16", "text/xml", "text/xml; charset=utf-8", "text/xml; charset=utf-16" })
31+
@ApiOperation(value = "creates an XmlItem", notes = "this route creates an XmlItem", tags={ "fake", })
32+
@ApiResponses(value = {
33+
@ApiResponse(code = 200, message = "successful operation", response = Void.class) })
34+
Response createXmlItem(@Valid XmlItem xmlItem);
35+
36+
@POST
3137
@Produces({ "*/*" })
3238
@ApiOperation(value = "", notes = "Test serialization of outer boolean types", tags={ "fake", })
3339
@ApiResponses(value = {
3440
@ApiResponse(code = 200, message = "Output boolean", response = Boolean.class) })
3541
Response fakeOuterBooleanSerialize(@Valid Boolean body);
3642

3743
@POST
38-
@Path("/outer/composite")
3944
@Produces({ "*/*" })
4045
@ApiOperation(value = "", notes = "Test serialization of object with outer number type", tags={ "fake", })
4146
@ApiResponses(value = {
4247
@ApiResponse(code = 200, message = "Output composite", response = OuterComposite.class) })
43-
Response fakeOuterCompositeSerialize(@Valid OuterComposite outerComposite);
48+
Response fakeOuterCompositeSerialize(@Valid OuterComposite body);
4449

4550
@POST
46-
@Path("/outer/number")
4751
@Produces({ "*/*" })
4852
@ApiOperation(value = "", notes = "Test serialization of outer number types", tags={ "fake", })
4953
@ApiResponses(value = {
5054
@ApiResponse(code = 200, message = "Output number", response = BigDecimal.class) })
5155
Response fakeOuterNumberSerialize(@Valid BigDecimal body);
5256

5357
@POST
54-
@Path("/outer/string")
5558
@Produces({ "*/*" })
5659
@ApiOperation(value = "", notes = "Test serialization of outer string types", tags={ "fake", })
5760
@ApiResponses(value = {
5861
@ApiResponse(code = 200, message = "Output string", response = String.class) })
5962
Response fakeOuterStringSerialize(@Valid String body);
6063

6164
@PUT
62-
@Path("/body-with-file-schema")
6365
@Consumes({ "application/json" })
6466
@ApiOperation(value = "", notes = "For this test, the body for this request much reference a schema named `File`.", tags={ "fake", })
6567
@ApiResponses(value = {
6668
@ApiResponse(code = 200, message = "Success", response = Void.class) })
67-
Response testBodyWithFileSchema(@Valid FileSchemaTestClass fileSchemaTestClass);
69+
Response testBodyWithFileSchema(@Valid FileSchemaTestClass body);
6870

6971
@PUT
70-
@Path("/body-with-query-params")
7172
@Consumes({ "application/json" })
7273
@ApiOperation(value = "", notes = "", tags={ "fake", })
7374
@ApiResponses(value = {
7475
@ApiResponse(code = 200, message = "Success", response = Void.class) })
75-
Response testBodyWithQueryParams(@QueryParam("query") @NotNull String query,@Valid User user);
76+
Response testBodyWithQueryParams(@QueryParam("query") @NotNull String query,@Valid User body);
7677

7778
@PATCH
7879
@Consumes({ "application/json" })
7980
@Produces({ "application/json" })
8081
@ApiOperation(value = "To test \"client\" model", notes = "To test \"client\" model", tags={ "fake", })
8182
@ApiResponses(value = {
8283
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
83-
Response testClientModel(@Valid Client client);
84+
Response testClientModel(@Valid Client body);
8485

8586
@POST
8687
@Consumes({ "application/x-www-form-urlencoded" })
@@ -98,35 +99,31 @@ public interface FakeApi {
9899
@ApiResponses(value = {
99100
@ApiResponse(code = 400, message = "Invalid request", response = Void.class),
100101
@ApiResponse(code = 404, message = "Not found", response = Void.class) })
101-
Response testEnumParameters(@HeaderParam("enum_header_string_array") @DefaultValue("new ArrayList<String>()") @ApiParam("Header parameter enum test (string array)") List<String> enumHeaderStringArray,@HeaderParam("enum_header_string") @DefaultValue("-efg") @ApiParam("Header parameter enum test (string)") String enumHeaderString,@QueryParam("enum_query_string_array") @DefaultValue("new ArrayList<String>()") @ApiParam("Query parameter enum test (string array)") List<String> enumQueryStringArray,@QueryParam("enum_query_string") @DefaultValue("-efg") @ApiParam("Query parameter enum test (string)") String enumQueryString,@QueryParam("enum_query_integer") @ApiParam("Query parameter enum test (double)") Integer enumQueryInteger,@QueryParam("enum_query_double") @ApiParam("Query parameter enum test (double)") Double enumQueryDouble,@FormParam(value = "enum_form_string_array") List<String> enumFormStringArray,@FormParam(value = "enum_form_string") String enumFormString);
102+
Response testEnumParameters(@HeaderParam("enum_header_string_array") @DefaultValue("new ArrayList<String>()") @ApiParam("Header parameter enum test (string array)") List<String> enumHeaderStringArray,@HeaderParam("enum_header_string") @DefaultValue("-efg") @ApiParam("Header parameter enum test (string)") String enumHeaderString,@QueryParam("enum_query_string_array") @ApiParam("Query parameter enum test (string array)") List<String> enumQueryStringArray,@QueryParam("enum_query_string") @DefaultValue("-efg") @ApiParam("Query parameter enum test (string)") String enumQueryString,@QueryParam("enum_query_integer") @ApiParam("Query parameter enum test (double)") Integer enumQueryInteger,@QueryParam("enum_query_double") @ApiParam("Query parameter enum test (double)") Double enumQueryDouble,@FormParam(value = "enum_form_string_array") List<String> enumFormStringArray,@FormParam(value = "enum_form_string") String enumFormString);
103+
104+
@DELETE
105+
@ApiOperation(value = "Fake endpoint to test group parameters (optional)", notes = "Fake endpoint to test group parameters (optional)", tags={ "fake", })
106+
@ApiResponses(value = {
107+
@ApiResponse(code = 400, message = "Someting wrong", response = Void.class) })
108+
Response testGroupParameters(@QueryParam("required_string_group") @NotNull @ApiParam("Required String in group parameters") Integer requiredStringGroup,@HeaderParam("required_boolean_group") @NotNull @ApiParam("Required Boolean in group parameters") Boolean requiredBooleanGroup,@QueryParam("required_int64_group") @NotNull @ApiParam("Required Integer in group parameters") Long requiredInt64Group,@QueryParam("string_group") @ApiParam("String in group parameters") Integer stringGroup,@HeaderParam("boolean_group") @ApiParam("Boolean in group parameters") Boolean booleanGroup,@QueryParam("int64_group") @ApiParam("Integer in group parameters") Long int64Group);
102109

103110
@POST
104-
@Path("/inline-additionalProperties")
105111
@Consumes({ "application/json" })
106112
@ApiOperation(value = "test inline additionalProperties", notes = "", tags={ "fake", })
107113
@ApiResponses(value = {
108114
@ApiResponse(code = 200, message = "successful operation", response = Void.class) })
109-
Response testInlineAdditionalProperties(@Valid Map<String, String> requestBody);
115+
Response testInlineAdditionalProperties(@Valid Map<String, String> param);
110116

111117
@GET
112-
@Path("/jsonFormData")
113118
@Consumes({ "application/x-www-form-urlencoded" })
114119
@ApiOperation(value = "test json serialization of form data", notes = "", tags={ "fake", })
115120
@ApiResponses(value = {
116121
@ApiResponse(code = 200, message = "successful operation", response = Void.class) })
117122
Response testJsonFormData(@FormParam(value = "param") String param,@FormParam(value = "param2") String param2);
118123

119-
@POST
120-
@Path("/{petId}/uploadImageWithRequiredFile")
121-
@Consumes({ "multipart/form-data" })
122-
@Produces({ "application/json" })
123-
@ApiOperation(value = "uploads an image (required)", notes = "", authorizations = {
124-
@Authorization(value = "petstore_auth", scopes = {
125-
@AuthorizationScope(scope = "write:pets", description = "modify pets in your account"),
126-
@AuthorizationScope(scope = "read:pets", description = "read your pets")
127-
})
128-
}, tags={ "pet" })
124+
@PUT
125+
@ApiOperation(value = "", notes = "To test the collection format in query parameters", tags={ "fake" })
129126
@ApiResponses(value = {
130-
@ApiResponse(code = 200, message = "successful operation", response = ModelApiResponse.class) })
131-
Response uploadFileWithRequiredFile(@PathParam("petId") @ApiParam("ID of pet to update") Long petId, @FormParam(value = "requiredFile") InputStream requiredFileInputStream,@FormParam(value = "additionalMetadata") String additionalMetadata);
127+
@ApiResponse(code = 200, message = "Success", response = Void.class) })
128+
Response testQueryParameterCollectionFormat(@QueryParam("pipe") @NotNull List<String> pipe,@QueryParam("ioutil") @NotNull List<String> ioutil,@QueryParam("http") @NotNull List<String> http,@QueryParam("url") @NotNull List<String> url,@QueryParam("context") @NotNull List<String> context);
132129
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.openapitools.api;
2+
3+
import org.openapitools.model.Client;
4+
5+
import javax.ws.rs.*;
6+
import javax.ws.rs.core.Response;
7+
8+
import io.swagger.annotations.*;
9+
10+
import java.io.InputStream;
11+
import java.util.Map;
12+
import java.util.List;
13+
import javax.validation.constraints.*;
14+
import javax.validation.Valid;
15+
16+
@Path("/FakeClassnameTags123")
17+
@Api(description = "the FakeClassnameTags123 API")
18+
public interface FakeClassnameTags123Api {
19+
20+
@PATCH
21+
@Consumes({ "application/json" })
22+
@Produces({ "application/json" })
23+
@ApiOperation(value = "To test class name in snake case", notes = "To test class name in snake case", authorizations = {
24+
@Authorization(value = "api_key_query")
25+
}, tags={ "fake_classname_tags 123#$%^" })
26+
@ApiResponses(value = {
27+
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
28+
Response testClassname(@Valid Client body);
29+
}

samples/server/petstore/jaxrs-spec-interface-response/src/gen/java/org/openapitools/api/FakeClassnameTestApi.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ public interface FakeClassnameTestApi {
2525
}, tags={ "fake_classname_tags 123#$%^" })
2626
@ApiResponses(value = {
2727
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
28-
Response testClassname(@Valid Client client);
28+
Response testClassname(@Valid Client body);
2929
}

0 commit comments

Comments
 (0)