add java8 and async options to springboot codegen

This commit is contained in:
cbornet 2016-06-10 17:12:56 +02:00
parent 851f2ef688
commit c2dbe44d08
16 changed files with 525 additions and 489 deletions

View File

@ -12,11 +12,15 @@ public class SpringBootServerCodegen extends JavaClientCodegen implements Codege
public static final String BASE_PACKAGE = "basePackage"; public static final String BASE_PACKAGE = "basePackage";
public static final String INTERFACE_ONLY = "interfaceOnly"; public static final String INTERFACE_ONLY = "interfaceOnly";
public static final String SINGLE_CONTENT_TYPES = "singleContentTypes"; public static final String SINGLE_CONTENT_TYPES = "singleContentTypes";
public static final String JAVA_8 = "java8";
public static final String ASYNC = "async";
protected String title = "Petstore Server"; protected String title = "Petstore Server";
protected String configPackage = ""; protected String configPackage = "";
protected String basePackage = ""; protected String basePackage = "";
protected boolean interfaceOnly = false; protected boolean interfaceOnly = false;
protected boolean singleContentTypes = false; protected boolean singleContentTypes = false;
protected boolean java8 = false;
protected boolean async = false;
protected String templateFileName = "api.mustache"; protected String templateFileName = "api.mustache";
public SpringBootServerCodegen() { public SpringBootServerCodegen() {
@ -45,11 +49,14 @@ public class SpringBootServerCodegen extends JavaClientCodegen implements Codege
cliOptions.add(new CliOption(BASE_PACKAGE, "base package for generated code")); cliOptions.add(new CliOption(BASE_PACKAGE, "base package for generated code"));
cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files.")); cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files."));
cliOptions.add(CliOption.newBoolean(SINGLE_CONTENT_TYPES, "Whether to select only one produces/consumes content-type by operation.")); cliOptions.add(CliOption.newBoolean(SINGLE_CONTENT_TYPES, "Whether to select only one produces/consumes content-type by operation."));
cliOptions.add(CliOption.newBoolean(JAVA_8, "use java8 default interface"));
cliOptions.add(CliOption.newBoolean(ASYNC, "use async Callable controllers"));
supportedLibraries.clear(); supportedLibraries.clear();
supportedLibraries.put(DEFAULT_LIBRARY, "Default Spring Boot server stub."); supportedLibraries.put(DEFAULT_LIBRARY, "Default Spring Boot server stub.");
supportedLibraries.put("j8-async", "Use async servlet feature and Java 8's default interface. Generating interface with service " + supportedLibraries.put("j8-async", "Use async servlet feature and Java 8's default interface. Generating interface with service " +
"declaration is useful when using Maven plugin. Just provide a implementation with @Controller to instantiate service."); "declaration is useful when using Maven plugin. Just provide a implementation with @Controller to instantiate service." +
"(DEPRECATED: use -Djava8=true,async=true instead)");
} }
@Override @Override
@ -92,6 +99,14 @@ public class SpringBootServerCodegen extends JavaClientCodegen implements Codege
this.setSingleContentTypes(Boolean.valueOf(additionalProperties.get(SINGLE_CONTENT_TYPES).toString())); this.setSingleContentTypes(Boolean.valueOf(additionalProperties.get(SINGLE_CONTENT_TYPES).toString()));
} }
if (additionalProperties.containsKey(JAVA_8)) {
this.setJava8(Boolean.valueOf(additionalProperties.get(JAVA_8).toString()));
}
if (additionalProperties.containsKey(ASYNC)) {
this.setAsync(Boolean.valueOf(additionalProperties.get(ASYNC).toString()));
}
supportingFiles.clear(); supportingFiles.clear();
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
@ -115,6 +130,19 @@ public class SpringBootServerCodegen extends JavaClientCodegen implements Codege
supportingFiles.add(new SupportingFile("application.properties", supportingFiles.add(new SupportingFile("application.properties",
("src.main.resources").replace(".", java.io.File.separator), "application.properties")); ("src.main.resources").replace(".", java.io.File.separator), "application.properties"));
} }
if ("j8-async".equals(getLibrary())) {
setJava8(true);
setAsync(true);
}
if (this.java8) {
additionalProperties.put("javaVersion", "1.8");
typeMapping.put("date", "LocalDate");
typeMapping.put("DateTime", "OffsetDateTime");
importMapping.put("LocalDate", "java.time.LocalDate");
importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
}
} }
@Override @Override
@ -228,23 +256,6 @@ public class SpringBootServerCodegen extends JavaClientCodegen implements Codege
} }
} }
} }
if("j8-async".equals(getLibrary())) {
apiTemplateFiles.remove(this.templateFileName);
this.templateFileName = "api-j8-async.mustache";
apiTemplateFiles.put(this.templateFileName, ".java");
int originalPomFileIdx = -1;
for (int i = 0; i < supportingFiles.size(); i++) {
if ("pom.xml".equals(supportingFiles.get(i).destinationFilename)) {
originalPomFileIdx = i;
break;
}
}
if (originalPomFileIdx > -1) {
supportingFiles.remove(originalPomFileIdx);
}
supportingFiles.add(new SupportingFile("pom-j8-async.mustache", "", "pom.xml"));
}
return objs; return objs;
} }
@ -266,14 +277,16 @@ public class SpringBootServerCodegen extends JavaClientCodegen implements Codege
this.basePackage = configPackage; this.basePackage = configPackage;
} }
public void setInterfaceOnly(boolean interfaceOnly) { public void setInterfaceOnly(boolean interfaceOnly) { this.interfaceOnly = interfaceOnly; }
this.interfaceOnly = interfaceOnly;
}
public void setSingleContentTypes(boolean singleContentTypes) { public void setSingleContentTypes(boolean singleContentTypes) {
this.singleContentTypes = singleContentTypes; this.singleContentTypes = singleContentTypes;
} }
public void setJava8(boolean java8) { this.java8 = java8; }
public void setAsync(boolean async) { this.async = async; }
@Override @Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) { public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// remove the import of "Object" to avoid compilation error // remove the import of "Object" to avoid compilation error

View File

@ -1,12 +1,12 @@
package {{apiPackage}}; package {{apiPackage}};
import {{modelPackage}}.*;
{{#imports}}import {{import}}; {{#imports}}import {{import}};
{{/imports}} {{/imports}}
import io.swagger.annotations.*; import io.swagger.annotations.*;
{{#java8}}
import org.springframework.http.HttpStatus;
{{/java8}}
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -18,11 +18,12 @@ import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
{{#async}}
import java.util.concurrent.Callable;
{{/async}}
import static org.springframework.http.MediaType.*;
@Api(value = "{{{baseName}}}", description = "the {{{baseName}}} API")
{{>generatedAnnotation}} {{>generatedAnnotation}}
@Api(value = "{{{baseName}}}", description = "the {{{baseName}}} API")
{{#operations}} {{#operations}}
public interface {{classname}} { public interface {{classname}} {
{{#operation}} {{#operation}}
@ -42,8 +43,11 @@ public interface {{classname}} {
produces = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }, {{/hasProduces}}{{#hasConsumes}} produces = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }, {{/hasProduces}}{{#hasConsumes}}
consumes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} },{{/hasConsumes}}{{/singleContentTypes}} consumes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} },{{/hasConsumes}}{{/singleContentTypes}}
method = RequestMethod.{{httpMethod}}) method = RequestMethod.{{httpMethod}})
ResponseEntity<{{>returnTypes}}> {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, {{#java8}}default {{/java8}}{{#async}}Callable<{{/async}}ResponseEntity<{{>returnTypes}}>{{#async}}>{{/async}} {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},
{{/hasMore}}{{/allParams}}); {{/hasMore}}{{/allParams}}){{^java8}};{{/java8}}{{#java8}} {
// do some magic!
return {{#async}}() -> {{/async}}new ResponseEntity<{{>returnTypes}}>(HttpStatus.OK);
}{{/java8}}
{{/operation}} {{/operation}}
} }

View File

@ -1,7 +1,6 @@
package {{apiPackage}}; package {{apiPackage}};
import {{modelPackage}}.*; {{^java8}}
{{#imports}}import {{import}}; {{#imports}}import {{import}};
{{/imports}} {{/imports}}
@ -9,7 +8,9 @@ import io.swagger.annotations.*;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
{{/java8}}
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
{{^java8}}
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestHeader;
@ -18,18 +19,26 @@ import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
{{#async}}
import java.util.concurrent.Callable;
{{/async}}{{/java8}}
@Controller
{{>generatedAnnotation}} {{>generatedAnnotation}}
@Controller
{{#operations}} {{#operations}}
public class {{classname}}Controller implements {{classname}} { public class {{classname}}Controller implements {{classname}} {
{{#operation}} {{^java8}}{{#operation}}
public ResponseEntity<{{>returnTypes}}> {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, public {{#async}}Callable<{{/async}}ResponseEntity<{{>returnTypes}}>{{#async}}>{{/async}} {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},
{{/hasMore}}{{/allParams}}) { {{/hasMore}}{{/allParams}}) {
// do some magic! // do some magic!{{^async}}
return new ResponseEntity<{{>returnTypes}}>(HttpStatus.OK);{{/async}}{{#async}}
return new Callable<ResponseEntity<{{>returnTypes}}>>() {
@Override
public ResponseEntity<{{>returnTypes}}> call() throws Exception {
return new ResponseEntity<{{>returnTypes}}>(HttpStatus.OK); return new ResponseEntity<{{>returnTypes}}>(HttpStatus.OK);
} }
};{{/async}}
{{/operation}} }
{{/operation}}{{/java8}}
} }
{{/operations}} {{/operations}}

View File

@ -7,6 +7,10 @@
<version>{{artifactVersion}}</version> <version>{{artifactVersion}}</version>
<properties> <properties>
<springfox-version>2.4.0</springfox-version> <springfox-version>2.4.0</springfox-version>
{{#java8}}
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
{{/java8}}
</properties> </properties>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -14,7 +18,8 @@
<version>1.3.3.RELEASE</version> <version>1.3.3.RELEASE</version>
</parent> </parent>
<build> <build>
<sourceDirectory>src/main/java</sourceDirectory>{{^interfaceOnly}} <sourceDirectory>src/main/java</sourceDirectory>
{{^interfaceOnly}}
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -27,7 +32,8 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
</plugins>{{/interfaceOnly}} </plugins>
{{/interfaceOnly}}
</build> </build>
<dependencies> <dependencies>
<dependency> <dependency>
@ -50,6 +56,14 @@
<artifactId>springfox-swagger-ui</artifactId> <artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-version}</version> <version>${springfox-version}</version>
</dependency> </dependency>
{{#java8}}
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
{{/java8}}
{{^java8}}
<dependency> <dependency>
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
@ -59,5 +73,6 @@
<groupId>joda-time</groupId> <groupId>joda-time</groupId>
<artifactId>joda-time</artifactId> <artifactId>joda-time</artifactId>
</dependency> </dependency>
{{/java8}}
</dependencies> </dependencies>
</project> </project>

View File

@ -33,9 +33,11 @@ public class SwaggerDocumentationConfig {
return new Docket(DocumentationType.SWAGGER_2) return new Docket(DocumentationType.SWAGGER_2)
.select() .select()
.apis(RequestHandlerSelectors.basePackage("{{apiPackage}}")) .apis(RequestHandlerSelectors.basePackage("{{apiPackage}}"))
.build() .build(){{#java8}}
.directModelSubstitute(java.time.LocalDate.class, java.sql.Date.class)
.directModelSubstitute(java.time.OffsetDateTime.class, java.util.Date.class){{/java8}}{{^java8}}
.directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class) .directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class)
.directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class) .directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class){{/java8}}
.apiInfo(apiInfo()); .apiInfo(apiInfo());
} }

View File

@ -12,6 +12,8 @@ public class SpringBootServerOptionsProvider extends JavaOptionsProvider {
public static final String LIBRARY_VALUE = "j8-async"; //FIXME hidding value from super class public static final String LIBRARY_VALUE = "j8-async"; //FIXME hidding value from super class
public static final String INTERFACE_ONLY = "true"; public static final String INTERFACE_ONLY = "true";
public static final String SINGLE_CONTENT_TYPES = "true"; public static final String SINGLE_CONTENT_TYPES = "true";
public static final String JAVA_8 = "true";
public static final String ASYNC = "true";
@Override @Override
public String getLanguage() { public String getLanguage() {
@ -26,6 +28,8 @@ public class SpringBootServerOptionsProvider extends JavaOptionsProvider {
options.put(CodegenConstants.LIBRARY, LIBRARY_VALUE); options.put(CodegenConstants.LIBRARY, LIBRARY_VALUE);
options.put(SpringBootServerCodegen.INTERFACE_ONLY, INTERFACE_ONLY); options.put(SpringBootServerCodegen.INTERFACE_ONLY, INTERFACE_ONLY);
options.put(SpringBootServerCodegen.SINGLE_CONTENT_TYPES, SINGLE_CONTENT_TYPES); options.put(SpringBootServerCodegen.SINGLE_CONTENT_TYPES, SINGLE_CONTENT_TYPES);
options.put(SpringBootServerCodegen.JAVA_8, JAVA_8);
options.put(SpringBootServerCodegen.ASYNC, ASYNC);
return options; return options;
} }

View File

@ -58,6 +58,10 @@ public class SpringBootServerOptionsTest extends JavaClientOptionsTest {
times = 1; times = 1;
clientCodegen.setSingleContentTypes(Boolean.valueOf(SpringBootServerOptionsProvider.SINGLE_CONTENT_TYPES)); clientCodegen.setSingleContentTypes(Boolean.valueOf(SpringBootServerOptionsProvider.SINGLE_CONTENT_TYPES));
times = 1; times = 1;
clientCodegen.setJava8(Boolean.valueOf(SpringBootServerOptionsProvider.JAVA_8));
times = 1;
clientCodegen.setAsync(Boolean.valueOf(SpringBootServerOptionsProvider.ASYNC));
times = 1;
}}; }};
} }

View File

@ -1,13 +1,10 @@
package io.swagger.api; package io.swagger.api;
import io.swagger.model.*;
import io.swagger.model.Pet; import io.swagger.model.Pet;
import io.swagger.model.ModelApiResponse; import io.swagger.model.ModelApiResponse;
import java.io.File; import java.io.File;
import io.swagger.annotations.*; import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -20,10 +17,8 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
import static org.springframework.http.MediaType.*;
@Api(value = "pet", description = "the pet API") @Api(value = "pet", description = "the pet API")
public interface PetApi { public interface PetApi {
@ApiOperation(value = "Add a new pet to the store", notes = "", response = Void.class, authorizations = { @ApiOperation(value = "Add a new pet to the store", notes = "", response = Void.class, authorizations = {

View File

@ -1,7 +1,5 @@
package io.swagger.api; package io.swagger.api;
import io.swagger.model.*;
import io.swagger.model.Pet; import io.swagger.model.Pet;
import io.swagger.model.ModelApiResponse; import io.swagger.model.ModelApiResponse;
import java.io.File; import java.io.File;
@ -20,9 +18,11 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@Controller
@Controller
public class PetApiController implements PetApi { public class PetApiController implements PetApi {
public ResponseEntity<Void> addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody Pet body) { public ResponseEntity<Void> addPet(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true ) @RequestBody Pet body) {
// do some magic! // do some magic!
return new ResponseEntity<Void>(HttpStatus.OK); return new ResponseEntity<Void>(HttpStatus.OK);

View File

@ -1,12 +1,9 @@
package io.swagger.api; package io.swagger.api;
import io.swagger.model.*;
import java.util.Map; import java.util.Map;
import io.swagger.model.Order; import io.swagger.model.Order;
import io.swagger.annotations.*; import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -19,10 +16,8 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
import static org.springframework.http.MediaType.*;
@Api(value = "store", description = "the store API") @Api(value = "store", description = "the store API")
public interface StoreApi { public interface StoreApi {
@ApiOperation(value = "Delete purchase order by ID", notes = "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", response = Void.class) @ApiOperation(value = "Delete purchase order by ID", notes = "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", response = Void.class)

View File

@ -1,7 +1,5 @@
package io.swagger.api; package io.swagger.api;
import io.swagger.model.*;
import java.util.Map; import java.util.Map;
import io.swagger.model.Order; import io.swagger.model.Order;
@ -19,9 +17,11 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@Controller
@Controller
public class StoreApiController implements StoreApi { public class StoreApiController implements StoreApi {
public ResponseEntity<Void> deleteOrder(@ApiParam(value = "ID of the order that needs to be deleted",required=true ) @PathVariable("orderId") String orderId) { public ResponseEntity<Void> deleteOrder(@ApiParam(value = "ID of the order that needs to be deleted",required=true ) @PathVariable("orderId") String orderId) {
// do some magic! // do some magic!
return new ResponseEntity<Void>(HttpStatus.OK); return new ResponseEntity<Void>(HttpStatus.OK);

View File

@ -1,12 +1,9 @@
package io.swagger.api; package io.swagger.api;
import io.swagger.model.*;
import io.swagger.model.User; import io.swagger.model.User;
import java.util.List; import java.util.List;
import io.swagger.annotations.*; import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -19,10 +16,8 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
import static org.springframework.http.MediaType.*;
@Api(value = "user", description = "the user API") @Api(value = "user", description = "the user API")
public interface UserApi { public interface UserApi {
@ApiOperation(value = "Create user", notes = "This can only be done by the logged in user.", response = Void.class) @ApiOperation(value = "Create user", notes = "This can only be done by the logged in user.", response = Void.class)

View File

@ -1,7 +1,5 @@
package io.swagger.api; package io.swagger.api;
import io.swagger.model.*;
import io.swagger.model.User; import io.swagger.model.User;
import java.util.List; import java.util.List;
@ -19,9 +17,11 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@Controller
@Controller
public class UserApiController implements UserApi { public class UserApiController implements UserApi {
public ResponseEntity<Void> createUser(@ApiParam(value = "Created user object" ,required=true ) @RequestBody User body) { public ResponseEntity<Void> createUser(@ApiParam(value = "Created user object" ,required=true ) @RequestBody User body) {
// do some magic! // do some magic!
return new ResponseEntity<Void>(HttpStatus.OK); return new ResponseEntity<Void>(HttpStatus.OK);