Skip to content

Commit

Permalink
[enhancement] [jaxrs-spec] Add builders to models (OpenAPITools#4930)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: William Cheng <[email protected]>
  • Loading branch information
3 people authored and michaelpro1 committed May 7, 2020
1 parent bb0147f commit c17fdd2
Show file tree
Hide file tree
Showing 150 changed files with 4,731 additions and 1,307 deletions.
1 change: 1 addition & 0 deletions docs/generators/jaxrs-cxf-cdi.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ sidebar_label: jaxrs-cxf-cdi
|disableHtmlEscaping|Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)| |false|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|fullJavaUtil|whether to use fully qualified name for classes under java.util. This option only works for Java API client| |false|
|generateBuilders|Whether to generate builders for models.| |false|
|generatePom|Whether to generate pom.xml if the file does not already exist.| |true|
|groupId|groupId in generated pom.xml| |org.openapitools|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |false|
Expand Down
1 change: 1 addition & 0 deletions docs/generators/jaxrs-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ sidebar_label: jaxrs-spec
|disableHtmlEscaping|Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)| |false|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|fullJavaUtil|whether to use fully qualified name for classes under java.util. This option only works for Java API client| |false|
|generateBuilders|Whether to generate builders for models.| |false|
|generatePom|Whether to generate pom.xml if the file does not already exist.| |true|
|groupId|groupId in generated pom.xml| |org.openapitools|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |false|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen {
public static final String USE_SWAGGER_ANNOTATIONS = "useSwaggerAnnotations";
public static final String JACKSON = "jackson";
public static final String OPEN_API_SPEC_FILE_LOCATION = "openApiSpecFileLocation";
public static final String GENERATE_BUILDERS = "generateBuilders";

public static final String QUARKUS_LIBRARY = "quarkus";
public static final String THORNTAIL_LIBRARY = "thorntail";
Expand All @@ -47,6 +48,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen {
private boolean interfaceOnly = false;
private boolean returnResponse = false;
private boolean generatePom = true;
private boolean generateBuilders = false;
private boolean useSwaggerAnnotations = true;
private boolean useJackson = false;
private String openApiSpecFileLocation = "src/main/openapi/openapi.yaml";
Expand Down Expand Up @@ -101,6 +103,7 @@ public JavaJAXRSSpecServerCodegen() {

cliOptions.add(library);
cliOptions.add(CliOption.newBoolean(GENERATE_POM, "Whether to generate pom.xml if the file does not already exist.").defaultValue(String.valueOf(generatePom)));
cliOptions.add(CliOption.newBoolean(GENERATE_BUILDERS, "Whether to generate builders for models.").defaultValue(String.valueOf(generateBuilders)));
cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files.").defaultValue(String.valueOf(interfaceOnly)));
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)));
cliOptions.add(CliOption.newBoolean(USE_SWAGGER_ANNOTATIONS, "Whether to generate Swagger annotations.", useSwaggerAnnotations));
Expand All @@ -124,14 +127,20 @@ public void processOpts() {
additionalProperties.remove(RETURN_RESPONSE);
}
}
if(QUARKUS_LIBRARY.equals(library) || THORNTAIL_LIBRARY.equals(library) || HELIDON_LIBRARY.equals(library) || OPEN_LIBERTY_LIBRARY.equals(library)) {
if (QUARKUS_LIBRARY.equals(library) || THORNTAIL_LIBRARY.equals(library) || HELIDON_LIBRARY.equals(library) || OPEN_LIBERTY_LIBRARY.equals(library)) {
useSwaggerAnnotations = false;
} else {
if (additionalProperties.containsKey(USE_SWAGGER_ANNOTATIONS)) {
useSwaggerAnnotations = Boolean.valueOf(additionalProperties.get(USE_SWAGGER_ANNOTATIONS).toString());
}
}
writePropertyBack(USE_SWAGGER_ANNOTATIONS, useSwaggerAnnotations);

if (additionalProperties.containsKey(GENERATE_BUILDERS)) {
generateBuilders = Boolean.valueOf(additionalProperties.get(GENERATE_BUILDERS).toString());
}
additionalProperties.put(GENERATE_BUILDERS, generateBuilders);

if (additionalProperties.containsKey(OPEN_API_SPEC_FILE_LOCATION)) {
openApiSpecFileLocation = additionalProperties.get(OPEN_API_SPEC_FILE_LOCATION).toString();
} else if(QUARKUS_LIBRARY.equals(library) || THORNTAIL_LIBRARY.equals(library) || HELIDON_LIBRARY.equals(library)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}
/**
{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/**
* {{description}}
**/{{/description}}{{#useSwaggerAnnotations}}
{{#description}}{{>additionalModelTypeAnnotations}}@ApiModel(description = "{{{description}}}"){{/description}}{{/useSwaggerAnnotations}}
**/{{/description}}
{{#useSwaggerAnnotations}}{{#description}}{{>additionalModelTypeAnnotations}}@ApiModel(description = "{{{description}}}"){{/description}}{{/useSwaggerAnnotations}}
{{>generatedAnnotation}}public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} {
{{#vars}}{{#isEnum}}{{^isContainer}}

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

{{>enumClass}}{{/mostInnerItems}}{{/isContainer}}{{/isEnum}}
private {{#useBeanValidation}}@Valid{{/useBeanValidation}} {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};{{/vars}}
private {{#useBeanValidation}}@Valid {{/useBeanValidation}}{{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};{{/vars}}

{{#vars}}
/**
{{#vars}}/**
{{#description}}
* {{description}}
{{/description}}
Expand All @@ -36,17 +34,22 @@ import com.fasterxml.jackson.annotation.JsonValue;
return this;
}

{{#generateBuilders}}public {{classname}}({{#vars}}{{{datatypeWithEnum}}} {{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}) {
{{#vars}}
this.{{name}} = {{name}};
{{/vars}}
}{{/generateBuilders}}

{{#vendorExtensions.x-extra-annotation}}{{{vendorExtensions.x-extra-annotation}}}{{/vendorExtensions.x-extra-annotation}}{{#useSwaggerAnnotations}}
@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{/useSwaggerAnnotations}}
@JsonProperty("{{baseName}}")
{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{getter}}() {
return {{name}};
}

public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
this.{{name}} = {{name}};
}

{{/vars}}
}{{/vars}}

@Override
public boolean equals(java.lang.Object o) {
Expand Down Expand Up @@ -88,4 +91,37 @@ import com.fasterxml.jackson.annotation.JsonValue;
}
return o.toString().replace("\n", "\n ");
}

{{#generateBuilders}}
public static Builder builder() {
return new Builder();
}

public static class Builder {
{{#vars}}
private {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
{{/vars}}

{{#vars}}
/**
{{#description}}
* {{description}}
{{/description}}
{{#minimum}}
* minimum: {{minimum}}
{{/minimum}}
{{#maximum}}
* maximum: {{maximum}}
{{/maximum}}
**/
public Builder {{name}}({{{datatypeWithEnum}}} {{name}}) {
this.{{name}} = {{name}};
return this;
}
{{/vars}}

public {{classname}} build() {
return new {{classname}}({{#vars}}{{name}}{{#hasMore}}, {{/hasMore}}{{/vars}});
}
}{{/generateBuilders}}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.3.1-SNAPSHOT
4.3.1-SNAPSHOT
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.0-SNAPSHOT
4.2.3-SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@
import javax.validation.constraints.*;
import javax.validation.Valid;

@Path("/another-fake")
@Api(description = "the another-fake API")
@Path("/AnotherFake")
@Api(description = "the AnotherFake API")
public interface AnotherFakeApi {

@PATCH
@Path("/dummy")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "To test special tags", notes = "To test special tags and operation ID starting with number", tags={ "$another-fake?" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
Response call123testSpecialTags(@Valid Client client);
Response call123testSpecialTags(@Valid Client body);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import org.openapitools.model.FileSchemaTestClass;
import org.joda.time.LocalDate;
import java.util.Map;
import org.openapitools.model.ModelApiResponse;
import org.openapitools.model.OuterComposite;
import org.openapitools.model.User;
import org.openapitools.model.XmlItem;

import javax.ws.rs.*;
import javax.ws.rs.core.Response;
Expand All @@ -22,65 +22,66 @@
import javax.validation.constraints.*;
import javax.validation.Valid;

@Path("/fake")
@Api(description = "the fake API")
@Path("/Fake")
@Api(description = "the Fake API")
public interface FakeApi {

@POST
@Path("/outer/boolean")
@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" })
@ApiOperation(value = "creates an XmlItem", notes = "this route creates an XmlItem", tags={ "fake", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = Void.class) })
Response createXmlItem(@Valid XmlItem xmlItem);

@POST
@Produces({ "*/*" })
@ApiOperation(value = "", notes = "Test serialization of outer boolean types", tags={ "fake", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Output boolean", response = Boolean.class) })
Response fakeOuterBooleanSerialize(@Valid Boolean body);

@POST
@Path("/outer/composite")
@Produces({ "*/*" })
@ApiOperation(value = "", notes = "Test serialization of object with outer number type", tags={ "fake", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Output composite", response = OuterComposite.class) })
Response fakeOuterCompositeSerialize(@Valid OuterComposite outerComposite);
Response fakeOuterCompositeSerialize(@Valid OuterComposite body);

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

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

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

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

@PATCH
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "To test \"client\" model", notes = "To test \"client\" model", tags={ "fake", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
Response testClientModel(@Valid Client client);
Response testClientModel(@Valid Client body);

@POST
@Consumes({ "application/x-www-form-urlencoded" })
Expand All @@ -98,35 +99,31 @@ public interface FakeApi {
@ApiResponses(value = {
@ApiResponse(code = 400, message = "Invalid request", response = Void.class),
@ApiResponse(code = 404, message = "Not found", response = Void.class) })
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);
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);

@DELETE
@ApiOperation(value = "Fake endpoint to test group parameters (optional)", notes = "Fake endpoint to test group parameters (optional)", tags={ "fake", })
@ApiResponses(value = {
@ApiResponse(code = 400, message = "Someting wrong", response = Void.class) })
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);

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

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

@POST
@Path("/{petId}/uploadImageWithRequiredFile")
@Consumes({ "multipart/form-data" })
@Produces({ "application/json" })
@ApiOperation(value = "uploads an image (required)", notes = "", authorizations = {
@Authorization(value = "petstore_auth", scopes = {
@AuthorizationScope(scope = "write:pets", description = "modify pets in your account"),
@AuthorizationScope(scope = "read:pets", description = "read your pets")
})
}, tags={ "pet" })
@PUT
@ApiOperation(value = "", notes = "To test the collection format in query parameters", tags={ "fake" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = ModelApiResponse.class) })
Response uploadFileWithRequiredFile(@PathParam("petId") @ApiParam("ID of pet to update") Long petId, @FormParam(value = "requiredFile") InputStream requiredFileInputStream,@FormParam(value = "additionalMetadata") String additionalMetadata);
@ApiResponse(code = 200, message = "Success", response = Void.class) })
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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.openapitools.api;

import org.openapitools.model.Client;

import javax.ws.rs.*;
import javax.ws.rs.core.Response;

import io.swagger.annotations.*;

import java.io.InputStream;
import java.util.Map;
import java.util.List;
import javax.validation.constraints.*;
import javax.validation.Valid;

@Path("/FakeClassnameTags123")
@Api(description = "the FakeClassnameTags123 API")
public interface FakeClassnameTags123Api {

@PATCH
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "To test class name in snake case", notes = "To test class name in snake case", authorizations = {
@Authorization(value = "api_key_query")
}, tags={ "fake_classname_tags 123#$%^" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
Response testClassname(@Valid Client body);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ public interface FakeClassnameTestApi {
}, tags={ "fake_classname_tags 123#$%^" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = Client.class) })
Response testClassname(@Valid Client client);
Response testClassname(@Valid Client body);
}
Loading

0 comments on commit c17fdd2

Please sign in to comment.