io.starter.ignite.generator.swagger.languages.StackGenSpringCodegen Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stackgen Show documentation
Show all versions of stackgen Show documentation
Starter StackGen CORE Service Generator
package io.starter.ignite.generator.swagger.languages;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenConstants;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenOperation;
import io.swagger.codegen.CodegenParameter;
import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.CodegenResponse;
import io.swagger.codegen.CodegenSecurity;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.SupportingFile;
import io.swagger.codegen.languages.AbstractJavaCodegen;
import io.swagger.codegen.languages.features.BeanValidationFeatures;
import io.swagger.codegen.languages.features.OptionalFeatures;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
/**
* customized Spring CodeGen for StackGen
*
* @author john
*
*/
public class StackGenSpringCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, OptionalFeatures {
protected static final Logger logger = LoggerFactory.getLogger(StackGenSpringCodegen.class);
public static final String DEFAULT_LIBRARY = "spring-boot";
public static final String TITLE = "title";
public static final String CONFIG_PACKAGE = "configPackage";
public static final String BASE_PACKAGE = "basePackage";
public static final String INTERFACE_ONLY = "interfaceOnly";
public static final String DELEGATE_PATTERN = "delegatePattern";
public static final String SINGLE_CONTENT_TYPES = "singleContentTypes";
public static final String JAVA_8 = "java8";
public static final String ASYNC = "async";
public static final String RESPONSE_WRAPPER = "responseWrapper";
public static final String USE_TAGS = "useTags";
public static final String SPRING_MVC_LIBRARY = "spring-mvc";
public static final String SPRING_CLOUD_LIBRARY = "spring-cloud";
public static final String IMPLICIT_HEADERS = "implicitHeaders";
public static final String SWAGGER_DOCKET_CONFIG = "swaggerDocketConfig";
protected String title = "swagger-petstore";
protected String configPackage = "io.swagger.configuration";
protected String basePackage = "io.swagger";
protected boolean interfaceOnly = false;
protected boolean delegatePattern = false;
protected boolean delegateMethod = false;
protected boolean singleContentTypes = false;
protected boolean java8 = false;
protected boolean async = false;
protected String responseWrapper = "";
protected boolean useTags = false;
protected boolean useBeanValidation = true;
protected boolean implicitHeaders = false;
protected boolean swaggerDocketConfig = false;
protected boolean useOptional = false;
public StackGenSpringCodegen() {
super();
outputFolder = "generated-code/javaSpring";
apiTestTemplateFiles.clear(); // TODO: add test template
embeddedTemplateDir = templateDir = "JavaSpring";
apiPackage = "io.swagger.api";
modelPackage = "io.swagger.model";
invokerPackage = "io.swagger.api";
artifactId = "swagger-spring";
additionalProperties.put(CONFIG_PACKAGE, configPackage);
additionalProperties.put(BASE_PACKAGE, basePackage);
// spring uses the jackson lib
additionalProperties.put("jackson", "true");
cliOptions.add(new CliOption(TITLE,
"server title name or client service name"));
cliOptions.add(new CliOption(CONFIG_PACKAGE,
"configuration package for generated code"));
cliOptions.add(new CliOption(BASE_PACKAGE,
"base package (invokerPackage) for generated code"));
cliOptions.add(CliOption
.newBoolean(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files."));
cliOptions.add(CliOption
.newBoolean(DELEGATE_PATTERN, "Whether to generate the server files using the delegate pattern"));
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"));
cliOptions.add(new CliOption(RESPONSE_WRAPPER,
"wrap the responses in given type (Future,Callable,CompletableFuture,ListenableFuture,DeferredResult,HystrixCommand,RxObservable,RxSingle or fully qualified type)"));
cliOptions.add(CliOption
.newBoolean(USE_TAGS, "use tags for creating interface and controller classnames"));
cliOptions.add(CliOption
.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations"));
cliOptions.add(CliOption
.newBoolean(IMPLICIT_HEADERS, "Use of @ApiImplicitParams for headers."));
cliOptions.add(CliOption
.newBoolean(SWAGGER_DOCKET_CONFIG, "Generate Spring Swagger Docket configuration class."));
cliOptions.add(CliOption
.newBoolean(USE_OPTIONAL, "Use Optional container for optional parameters"));
supportedLibraries
.put(DEFAULT_LIBRARY, "Spring-boot Server application using the SpringFox integration.");
supportedLibraries
.put(SPRING_MVC_LIBRARY, "Spring-MVC Server application using the SpringFox integration.");
supportedLibraries
.put(SPRING_CLOUD_LIBRARY, "Spring-Cloud-Feign client with Spring-Boot auto-configured settings.");
setLibrary(DEFAULT_LIBRARY);
CliOption library = new CliOption(CodegenConstants.LIBRARY,
"library template (sub-template) to use");
library.setDefault(DEFAULT_LIBRARY);
library.setEnum(supportedLibraries);
library.setDefault(DEFAULT_LIBRARY);
cliOptions.add(library);
}
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}
@Override
public String getName() {
return "spring";
}
@Override
public String getHelp() {
return "Generates a Java SpringBoot Server application using the SpringFox integration.";
}
@Override
public void processOpts() {
// Process java8 option before common java ones to change
// the default dateLibrary to java8.
if (additionalProperties.containsKey(JAVA_8)) {
this.setJava8(Boolean.valueOf(additionalProperties.get(JAVA_8).toString()));
}
if (this.java8) {
additionalProperties.put("javaVersion", "1.8");
additionalProperties.put("jdk8", "true");
if (!additionalProperties.containsKey(DATE_LIBRARY)) {
setDateLibrary("java8");
}
}
// set invokerPackage as basePackage
if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
this.setBasePackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
additionalProperties.put(BASE_PACKAGE, basePackage);
logger.info("Set base package to invoker package (" + basePackage + ")");
}
super.processOpts();
// clear model and api doc template as this codegen
// does not support auto-generated markdown doc at the
// moment
// TODO: add doc templates
modelDocTemplateFiles.remove("model_doc.mustache");
apiDocTemplateFiles.remove("api_doc.mustache");
if (additionalProperties.containsKey(TITLE)) {
this.setTitle((String) additionalProperties.get(TITLE));
}
if (additionalProperties.containsKey(CONFIG_PACKAGE)) {
this.setConfigPackage((String) additionalProperties.get(CONFIG_PACKAGE));
}
if (additionalProperties.containsKey(BASE_PACKAGE)) {
this.setBasePackage((String) additionalProperties.get(BASE_PACKAGE));
}
if (additionalProperties.containsKey(INTERFACE_ONLY)) {
this.setInterfaceOnly(Boolean.valueOf(additionalProperties.get(INTERFACE_ONLY).toString()));
}
if (additionalProperties.containsKey(DELEGATE_PATTERN)) {
this.setDelegatePattern(Boolean.valueOf(additionalProperties.get(DELEGATE_PATTERN).toString()));
}
if (additionalProperties.containsKey(SINGLE_CONTENT_TYPES)) {
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()));
}
if (additionalProperties.containsKey(RESPONSE_WRAPPER)) {
this.setResponseWrapper((String) additionalProperties.get(RESPONSE_WRAPPER));
}
if (additionalProperties.containsKey(USE_TAGS)) {
this.setUseTags(Boolean.valueOf(additionalProperties.get(USE_TAGS).toString()));
}
if (additionalProperties.containsKey(USE_BEANVALIDATION)) {
this.setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION));
}
if (additionalProperties.containsKey(USE_OPTIONAL)) {
this.setUseOptional(convertPropertyToBoolean(USE_OPTIONAL));
}
if (useBeanValidation) {
writePropertyBack(USE_BEANVALIDATION, useBeanValidation);
}
if (additionalProperties.containsKey(IMPLICIT_HEADERS)) {
this.setImplicitHeaders(Boolean.valueOf(additionalProperties.get(IMPLICIT_HEADERS).toString()));
}
if (additionalProperties.containsKey(SWAGGER_DOCKET_CONFIG)) {
this.setSwaggerDocketConfig(Boolean.valueOf(additionalProperties.get(SWAGGER_DOCKET_CONFIG).toString()));
}
typeMapping.put("file", "Resource");
importMapping.put("Resource", "org.springframework.core.io.Resource");
if (useOptional) {
writePropertyBack(USE_OPTIONAL, useOptional);
}
if (this.interfaceOnly && this.delegatePattern) {
if (this.java8) {
this.delegateMethod = true;
additionalProperties.put("delegate-method", true);
} else {
throw new IllegalArgumentException(
String.format("Can not generate code with `%s` and `%s` true while `%s` is false.",
DELEGATE_PATTERN, INTERFACE_ONLY, JAVA_8));
}
}
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
if (!this.interfaceOnly) {
if (library.equals(DEFAULT_LIBRARY)) {
supportingFiles.add(new SupportingFile("homeController.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"HomeController.java"));
supportingFiles.add(new SupportingFile("swagger2SpringBoot.mustache",
(sourceFolder + File.separator + basePackage).replace(".", java.io.File.separator),
"Swagger2SpringBoot.java"));
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache",
(sourceFolder + File.separator + basePackage).replace(".", java.io.File.separator),
"RFC3339DateFormat.java"));
supportingFiles.add(new SupportingFile("application.mustache",
("src.main.resources").replace(".", java.io.File.separator), "application.properties"));
}
if (library.equals(SPRING_MVC_LIBRARY)) {
supportingFiles.add(new SupportingFile("webApplication.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"WebApplication.java"));
supportingFiles.add(new SupportingFile("webMvcConfiguration.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"WebMvcConfiguration.java"));
supportingFiles.add(new SupportingFile("swaggerUiConfiguration.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"SwaggerUiConfiguration.java"));
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"RFC3339DateFormat.java"));
supportingFiles.add(new SupportingFile("application.properties",
("src.main.resources").replace(".", java.io.File.separator), "swagger.properties"));
}
if (library.equals(SPRING_CLOUD_LIBRARY)) {
supportingFiles.add(new SupportingFile("apiKeyRequestInterceptor.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"ApiKeyRequestInterceptor.java"));
supportingFiles.add(new SupportingFile("clientConfiguration.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"ClientConfiguration.java"));
apiTemplateFiles.put("apiClient.mustache", "Client.java");
if (!additionalProperties.containsKey(SINGLE_CONTENT_TYPES)) {
additionalProperties.put(SINGLE_CONTENT_TYPES, "true");
this.setSingleContentTypes(true);
}
} else {
apiTemplateFiles.put("apiController.mustache", "Controller.java");
supportingFiles.add(new SupportingFile("apiException.mustache",
(sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator),
"ApiException.java"));
supportingFiles.add(new SupportingFile("apiResponseMessage.mustache",
(sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator),
"ApiResponseMessage.java"));
supportingFiles.add(new SupportingFile("notFoundException.mustache",
(sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator),
"NotFoundException.java"));
supportingFiles.add(new SupportingFile("apiOriginFilter.mustache",
(sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator),
"ApiOriginFilter.java"));
supportingFiles.add(new SupportingFile("swaggerDocumentationConfig.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"SwaggerDocumentationConfig.java"));
}
} else if (this.swaggerDocketConfig && !library.equals(SPRING_CLOUD_LIBRARY)) {
supportingFiles.add(new SupportingFile("swaggerDocumentationConfig.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"SwaggerDocumentationConfig.java"));
}
if ("threetenbp".equals(dateLibrary)) {
supportingFiles.add(new SupportingFile("customInstantDeserializer.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"CustomInstantDeserializer.java"));
if (library.equals(DEFAULT_LIBRARY) || library.equals(SPRING_CLOUD_LIBRARY)) {
supportingFiles.add(new SupportingFile("jacksonConfiguration.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"JacksonConfiguration.java"));
}
}
if ((!this.delegatePattern && this.java8) || this.delegateMethod) {
additionalProperties.put("jdk8-no-delegate", true);
}
if (this.delegatePattern && !this.delegateMethod) {
additionalProperties.put("isDelegate", "true");
apiTemplateFiles.put("apiDelegate.mustache", "Delegate.java");
}
if (this.java8) {
additionalProperties.put("javaVersion", "1.8");
additionalProperties.put("jdk8", "true");
if (this.async) {
additionalProperties.put(RESPONSE_WRAPPER, "CompletableFuture");
}
} else if (this.async) {
additionalProperties.put(RESPONSE_WRAPPER, "Callable");
}
// Some well-known Spring or Spring-Cloud response wrappers
switch (this.responseWrapper) {
case "Future":
case "Callable":
case "CompletableFuture":
additionalProperties.put(RESPONSE_WRAPPER, "java.util.concurrent" + this.responseWrapper);
break;
case "ListenableFuture":
additionalProperties.put(RESPONSE_WRAPPER, "org.springframework.util.concurrent.ListenableFuture");
break;
case "DeferredResult":
additionalProperties.put(RESPONSE_WRAPPER, "org.springframework.web.context.request.async.DeferredResult");
break;
case "HystrixCommand":
additionalProperties.put(RESPONSE_WRAPPER, "com.netflix.hystrix.HystrixCommand");
break;
case "RxObservable":
additionalProperties.put(RESPONSE_WRAPPER, "rx.Observable");
break;
case "RxSingle":
additionalProperties.put(RESPONSE_WRAPPER, "rx.Single");
break;
default:
break;
}
// add lambda for mustache templates
additionalProperties.put("lambdaEscapeDoubleQuote", new Mustache.Lambda() {
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
writer.write(fragment.execute().replaceAll("\"", Matcher.quoteReplacement("\\\"")));
}
});
additionalProperties.put("lambdaRemoveLineBreak", new Mustache.Lambda() {
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
writer.write(fragment.execute().replaceAll("\\r|\\n", ""));
}
});
}
@Override
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co,
Map> operations) {
if ((library.equals(DEFAULT_LIBRARY) || library.equals(SPRING_MVC_LIBRARY)) && !useTags) {
String basePath = resourcePath;
if (basePath.startsWith("/")) {
basePath = basePath.substring(1);
}
int pos = basePath.indexOf("/");
if (pos > 0) {
basePath = basePath.substring(0, pos);
}
if (basePath.equals("")) {
basePath = "default";
} else {
co.subresourceOperation = !co.path.isEmpty();
}
List opList = operations.get(basePath);
if (opList == null) {
opList = new ArrayList();
operations.put(basePath, opList);
}
opList.add(co);
co.baseName = basePath;
} else {
super.addOperationToGroup(tag, resourcePath, operation, co, operations);
}
}
@Override
public void preprocessSwagger(Swagger swagger) {
super.preprocessSwagger(swagger);
if ("/".equals(swagger.getBasePath())) {
swagger.setBasePath("");
}
if (!additionalProperties.containsKey(TITLE)) {
// From the title, compute a reasonable name for the package
// and the API
String title = swagger.getInfo().getTitle();
// Drop any API suffix
if (title != null) {
title = title.trim().replace(" ", "-");
if (title.toUpperCase().endsWith("API")) {
title = title.substring(0, title.length() - 3);
}
this.title = camelize(sanitizeName(title), true);
}
additionalProperties.put(TITLE, this.title);
}
String host = swagger.getHost();
String port = "8080";
if (host != null) {
String[] parts = host.split(":");
if (parts.length > 1) {
port = parts[1];
}
}
this.additionalProperties.put("serverPort", port);
if (swagger.getPaths() != null) {
for (String pathname : swagger.getPaths().keySet()) {
Path path = swagger.getPath(pathname);
if (path.getOperations() != null) {
for (Operation operation : path.getOperations()) {
if (operation.getTags() != null) {
List