add java generator

This commit is contained in:
wing328
2018-04-03 15:45:24 +08:00
parent ffecaa1b0b
commit d4cd0bdc3e
18 changed files with 829 additions and 48 deletions

View File

@@ -68,7 +68,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
protected boolean hideGenerationTimestamp = false;
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
protected boolean supportJava6= false;
protected boolean supportJava6 = false;
public AbstractJavaCodegen() {
super();
@@ -80,22 +80,22 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
apiDocTemplateFiles.put("api_doc.mustache", ".md");
setReservedWordsLowerCase(
Arrays.asList(
// used as internal variables, can collide with parameter names
"localVarPath", "localVarQueryParams", "localVarCollectionQueryParams",
"localVarHeaderParams", "localVarFormParams", "localVarPostBody",
"localVarAccepts", "localVarAccept", "localVarContentTypes",
"localVarContentType", "localVarAuthNames", "localReturnType",
"ApiClient", "ApiException", "ApiResponse", "Configuration", "StringUtil",
Arrays.asList(
// used as internal variables, can collide with parameter names
"localVarPath", "localVarQueryParams", "localVarCollectionQueryParams",
"localVarHeaderParams", "localVarFormParams", "localVarPostBody",
"localVarAccepts", "localVarAccept", "localVarContentTypes",
"localVarContentType", "localVarAuthNames", "localReturnType",
"ApiClient", "ApiException", "ApiResponse", "Configuration", "StringUtil",
// language reserved words
"abstract", "continue", "for", "new", "switch", "assert",
"default", "if", "package", "synchronized", "boolean", "do", "goto", "private",
"this", "break", "double", "implements", "protected", "throw", "byte", "else",
"import", "public", "throws", "case", "enum", "instanceof", "return", "transient",
"catch", "extends", "int", "short", "try", "char", "final", "interface", "static",
"void", "class", "finally", "long", "strictfp", "volatile", "const", "float",
"native", "super", "while", "null")
// language reserved words
"abstract", "continue", "for", "new", "switch", "assert",
"default", "if", "package", "synchronized", "boolean", "do", "goto", "private",
"this", "break", "double", "implements", "protected", "throw", "byte", "else",
"import", "public", "throws", "case", "enum", "instanceof", "return", "transient",
"catch", "extends", "int", "short", "try", "char", "final", "interface", "static",
"void", "class", "finally", "long", "strictfp", "volatile", "const", "float",
"native", "super", "while", "null")
);
languageSpecificPrimitives = new HashSet<String>(
@@ -174,13 +174,13 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
} else if (additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
// guess from api package
String derviedInvokerPackage = deriveInvokerPackageName((String)additionalProperties.get(CodegenConstants.API_PACKAGE));
String derviedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.API_PACKAGE));
this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derviedInvokerPackage);
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
LOGGER.info("Invoker Package Name, originally not set, is now dervied from api package name: " + derviedInvokerPackage);
} else if (additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) {
// guess from model package
String derviedInvokerPackage = deriveInvokerPackageName((String)additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
String derviedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derviedInvokerPackage);
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
LOGGER.info("Invoker Package Name, originally not set, is now dervied from model package name: " + derviedInvokerPackage);
@@ -292,7 +292,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
this.setLibrary((String) additionalProperties.get(CodegenConstants.LIBRARY));
}
if(additionalProperties.containsKey(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING)) {
if (additionalProperties.containsKey(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING)) {
this.setSerializeBigDecimalAsString(Boolean.valueOf(additionalProperties.get(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING).toString()));
}
@@ -365,16 +365,16 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
// used later in recursive import in postProcessingModels
importMapping.put("com.fasterxml.jackson.annotation.JsonProperty", "com.fasterxml.jackson.annotation.JsonCreator");
if(additionalProperties.containsKey(JAVA8_MODE)) {
if (additionalProperties.containsKey(JAVA8_MODE)) {
setJava8Mode(Boolean.parseBoolean(additionalProperties.get(JAVA8_MODE).toString()));
if ( java8Mode ) {
if (java8Mode) {
additionalProperties.put("java8", "true");
}
}
if(additionalProperties.containsKey(WITH_XML)) {
if (additionalProperties.containsKey(WITH_XML)) {
setWithXml(Boolean.parseBoolean(additionalProperties.get(WITH_XML).toString()));
if ( withXml ) {
if (withXml) {
additionalProperties.put(WITH_XML, "true");
}
}
@@ -435,7 +435,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public String escapeReservedWord(String name) {
if(this.reservedWordsMappings().containsKey(name)) {
if (this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name;
@@ -503,8 +503,8 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
return "propertyClass";
}
if("_".equals(name)) {
name = "_u";
if ("_".equals(name)) {
name = "_u";
}
// if it's all uppper case, do nothing
@@ -512,7 +512,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
return name;
}
if(startsWithTwoUppercaseLetters(name)){
if (startsWithTwoUppercaseLetters(name)) {
name = name.substring(0, 2).toLowerCase() + name.substring(2);
}
@@ -530,7 +530,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
private boolean startsWithTwoUppercaseLetters(String name) {
boolean startsWithTwoUppercaseLetters = false;
if(name.length() > 1) {
if (name.length() > 1) {
startsWithTwoUppercaseLetters = name.substring(0, 2).equals(name.substring(0, 2).toUpperCase());
}
return startsWithTwoUppercaseLetters;
@@ -679,7 +679,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
return p.getDefault().toString();
}
}
return "null";
return "null";
} else if (p instanceof NumberSchema) {
if (p.getDefault() != null) {
if (SchemaTypeUtil.FLOAT_FORMAT.equals(p.getFormat())) {
@@ -777,7 +777,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public String toExampleValue(Schema p) {
if(p.getExample() != null) {
if (p.getExample() != null) {
return escapeText(p.getExample().toString());
} else {
return super.toExampleValue(p);
@@ -823,7 +823,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public CodegenModel fromModel(String name, Schema model, Map<String, Schema> allDefinitions) {
CodegenModel codegenModel = super.fromModel(name, model, allDefinitions);
if(codegenModel.description != null) {
if (codegenModel.description != null) {
codegenModel.imports.add("ApiModel");
}
if (codegenModel.discriminator != null && additionalProperties.containsKey("jackson")) {
@@ -840,7 +840,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
if(serializeBigDecimalAsString) {
if (serializeBigDecimalAsString) {
if (property.baseType.equals("BigDecimal")) {
// we serialize BigDecimal as `string` to avoid precision loss
property.vendorExtensions.put("extraAnnotation", "@JsonSerialize(using = ToStringSerializer.class)");
@@ -859,7 +859,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
}
}
if(!BooleanUtils.toBoolean(model.isEnum)) {
if (!BooleanUtils.toBoolean(model.isEnum)) {
// needed by all pojos, but not enums
model.imports.add("ApiModelProperty");
model.imports.add("ApiModel");
@@ -867,7 +867,8 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
}
@Override
public void postProcessParameter(CodegenParameter parameter) { }
public void postProcessParameter(CodegenParameter parameter) {
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
@@ -882,7 +883,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
// if the import package happens to be found in the importMapping (key)
// add the corresponding import package to the list
if (importMapping.containsKey(_import)) {
Map<String, String> newImportMap= new HashMap<String, String>();
Map<String, String> newImportMap = new HashMap<String, String>();
newImportMap.put("import", importMapping.get(_import));
listIterator.add(newImportMap);
}
@@ -897,10 +898,10 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
// imported in the template already.
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
Pattern pattern = Pattern.compile("java\\.util\\.(List|ArrayList|Map|HashMap)");
for (Iterator<Map<String, String>> itr = imports.iterator(); itr.hasNext();) {
for (Iterator<Map<String, String>> itr = imports.iterator(); itr.hasNext(); ) {
String _import = itr.next().get("import");
if (pattern.matcher(_import).matches()) {
itr.remove();
itr.remove();
}
}
return objs;
@@ -908,19 +909,19 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public void preprocessOpenAPI(OpenAPI openAPI) {
if (openAPI == null || openAPI.getPaths() == null){
if (openAPI == null || openAPI.getPaths() == null) {
return;
}
for (String pathname : openAPI.getPaths().keySet()) {
PathItem path = openAPI.getPaths().get(pathname);
if (path.readOperations() == null){
if (path.readOperations() == null) {
continue;
}
for (Operation operation : path.readOperations()) {
if (hasBodyParameter(operation) || hasFormParameter(operation)){
if (hasBodyParameter(operation) || hasFormParameter(operation)) {
String defaultContentType = hasFormParameter(operation) ? "application/x-www-form-urlencoded" : "application/json";
List<String> consumes = new ArrayList<String>(getConsumesInfo(operation));
String contentType = consumes == null || consumes.isEmpty() ? defaultContentType : consumes.get(0);
String contentType = consumes == null || consumes.isEmpty() ? defaultContentType : consumes.get(0);
operation.getExtensions().put("x-contentType", contentType);
}
String accepts = getAccept(operation);
@@ -980,7 +981,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
// number
if ("Integer".equals(datatype) || "Long".equals(datatype) ||
"Float".equals(datatype) || "Double".equals(datatype)) {
"Float".equals(datatype) || "Double".equals(datatype)) {
String varName = "NUMBER_" + value;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
@@ -1027,7 +1028,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
// Because the child models extend the parents, the enums will be available via the parent.
// Only bother with reconciliation if the parent model has enums.
if (!parentCodegenModel.hasEnums) {
if (!parentCodegenModel.hasEnums) {
return codegenModel;
}
@@ -1055,10 +1056,10 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
}
}
if(removedChildEnum) {
if (removedChildEnum) {
// If we removed an entry from this model's vars, we need to ensure hasMore is updated
int count = 0, numVars = codegenProperties.size();
for(CodegenProperty codegenProperty : codegenProperties) {
for (CodegenProperty codegenProperty : codegenProperties) {
count += 1;
codegenProperty.hasMore = (count < numVars) ? true : false;
}
@@ -1070,7 +1071,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
private static String sanitizePackageName(String packageName) {
packageName = packageName.trim(); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
packageName = packageName.replaceAll("[^a-zA-Z0-9_\\.]", "_");
if(Strings.isNullOrEmpty(packageName)) {
if (Strings.isNullOrEmpty(packageName)) {
return "invalidPackageName";
}
return packageName;
@@ -1200,7 +1201,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
StringBuilder sb = new StringBuilder();
String delim = "";
for (String p : Arrays.copyOf(parts, parts.length-1)) {
for (String p : Arrays.copyOf(parts, parts.length - 1)) {
sb.append(delim).append(p);
delim = ".";
}
@@ -1221,7 +1222,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
booleanValue = Boolean.valueOf(additionalProperties.get(propertyKey).toString());
}
return booleanValue;
return booleanValue;
}
public void writePropertyBack(String propertyKey, boolean value) {

View File

@@ -0,0 +1,611 @@
package org.openapitools.codegen.languages;
import static java.util.Collections.sort;
import com.google.common.collect.LinkedListMultimap;
import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
import org.openapitools.codegen.languages.features.GzipFeatures;
import org.openapitools.codegen.languages.features.PerformBeanValidationFeatures;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import java.util.regex.Pattern;
public class JavaClientCodegen extends AbstractJavaCodegen
implements BeanValidationFeatures, PerformBeanValidationFeatures,
GzipFeatures {
static final String MEDIA_TYPE = "mediaType";
@SuppressWarnings("hiding")
private static final Logger LOGGER = LoggerFactory.getLogger(JavaClientCodegen.class);
public static final String USE_RX_JAVA = "useRxJava";
public static final String USE_RX_JAVA2 = "useRxJava2";
public static final String DO_NOT_USE_RX = "doNotUseRx";
public static final String USE_PLAY_WS = "usePlayWS";
public static final String PLAY_VERSION = "playVersion";
public static final String PARCELABLE_MODEL = "parcelableModel";
public static final String USE_RUNTIME_EXCEPTION = "useRuntimeException";
public static final String PLAY_24 = "play24";
public static final String PLAY_25 = "play25";
public static final String RETROFIT_1 = "retrofit";
public static final String RETROFIT_2 = "retrofit2";
public static final String REST_ASSURED = "rest-assured";
protected String gradleWrapperPackage = "gradle.wrapper";
protected boolean useRxJava = false;
protected boolean useRxJava2 = false;
protected boolean doNotUseRx = true; // backwards compatibility for swagger configs that specify neither rx1 nor rx2 (mustache does not allow for boolean operators so we need this extra field)
protected boolean usePlayWS = false;
protected String playVersion = PLAY_25;
protected boolean parcelableModel = false;
protected boolean useBeanValidation = false;
protected boolean performBeanValidation = false;
protected boolean useGzipFeature = false;
protected boolean useRuntimeException = false;
public JavaClientCodegen() {
super();
outputFolder = "generated-code" + File.separator + "java";
embeddedTemplateDir = templateDir = "Java";
invokerPackage = "io.swagger.client";
artifactId = "swagger-java-client";
apiPackage = "io.swagger.client.api";
modelPackage = "io.swagger.client.model";
cliOptions.add(CliOption.newBoolean(USE_RX_JAVA, "Whether to use the RxJava adapter with the retrofit2 library."));
cliOptions.add(CliOption.newBoolean(USE_RX_JAVA2, "Whether to use the RxJava2 adapter with the retrofit2 library."));
cliOptions.add(CliOption.newBoolean(PARCELABLE_MODEL, "Whether to generate models for Android that implement Parcelable with the okhttp-gson library."));
cliOptions.add(CliOption.newBoolean(USE_PLAY_WS, "Use Play! Async HTTP client (Play WS API)"));
cliOptions.add(CliOption.newString(PLAY_VERSION, "Version of Play! Framework (possible values \"play24\", \"play25\")"));
cliOptions.add(CliOption.newBoolean(SUPPORT_JAVA6, "Whether to support Java6 with the Jersey1 library."));
cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations"));
cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION, "Perform BeanValidation"));
cliOptions.add(CliOption.newBoolean(USE_GZIP_FEATURE, "Send gzip-encoded requests"));
cliOptions.add(CliOption.newBoolean(USE_RUNTIME_EXCEPTION, "Use RuntimeException instead of Exception"));
supportedLibraries.put("jersey1", "HTTP client: Jersey client 1.19.4. JSON processing: Jackson 2.8.9. Enable Java6 support using '-DsupportJava6=true'. Enable gzip request encoding using '-DuseGzipFeature=true'.");
supportedLibraries.put("feign", "HTTP client: OpenFeign 9.4.0. JSON processing: Jackson 2.8.9");
supportedLibraries.put("jersey2", "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.8.9");
supportedLibraries.put("okhttp-gson", "HTTP client: OkHttp 2.7.5. JSON processing: Gson 2.8.1. Enable Parcelable models on Android using '-DparcelableModel=true'. Enable gzip request encoding using '-DuseGzipFeature=true'.");
supportedLibraries.put(RETROFIT_1, "HTTP client: OkHttp 2.7.5. JSON processing: Gson 2.3.1 (Retrofit 1.9.0). IMPORTANT NOTE: retrofit1.x is no longer actively maintained so please upgrade to 'retrofit2' instead.");
supportedLibraries.put(RETROFIT_2, "HTTP client: OkHttp 3.8.0. JSON processing: Gson 2.6.1 (Retrofit 2.3.0). Enable the RxJava adapter using '-DuseRxJava[2]=true'. (RxJava 1.x or 2.x)");
supportedLibraries.put("resttemplate", "HTTP client: Spring RestTemplate 4.3.9-RELEASE. JSON processing: Jackson 2.8.9");
supportedLibraries.put("resteasy", "HTTP client: Resteasy client 3.1.3.Final. JSON processing: Jackson 2.8.9");
supportedLibraries.put("vertx", "HTTP client: VertX client 3.2.4. JSON processing: Jackson 2.8.9");
supportedLibraries.put("google-api-client", "HTTP client: Google API client 1.23.0. JSON processing: Jackson 2.8.9");
supportedLibraries.put("rest-assured", "HTTP client: rest-assured : 3.0.6. JSON processing: Gson 2.6.1. Only for Java8");
CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use");
libraryOption.setEnum(supportedLibraries);
// set okhttp-gson as the default
libraryOption.setDefault("okhttp-gson");
cliOptions.add(libraryOption);
setLibrary("okhttp-gson");
}
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "java";
}
@Override
public String getHelp() {
return "Generates a Java client library.";
}
@Override
public void processOpts() {
super.processOpts();
if (additionalProperties.containsKey(USE_RX_JAVA) && additionalProperties.containsKey(USE_RX_JAVA2)) {
LOGGER.warn("You specified both RxJava versions 1 and 2 but they are mutually exclusive. Defaulting to v2.");
} else if (additionalProperties.containsKey(USE_RX_JAVA)) {
this.setUseRxJava(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA).toString()));
}
if (additionalProperties.containsKey(USE_RX_JAVA2)) {
this.setUseRxJava2(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA2).toString()));
}
if (!useRxJava && !useRxJava2) {
additionalProperties.put(DO_NOT_USE_RX, true);
}
if (additionalProperties.containsKey(USE_PLAY_WS)) {
this.setUsePlayWS(Boolean.valueOf(additionalProperties.get(USE_PLAY_WS).toString()));
}
additionalProperties.put(USE_PLAY_WS, usePlayWS);
if (additionalProperties.containsKey(PLAY_VERSION)) {
this.setPlayVersion(additionalProperties.get(PLAY_VERSION).toString());
}
additionalProperties.put(PLAY_VERSION, playVersion);
if (additionalProperties.containsKey(PARCELABLE_MODEL)) {
this.setParcelableModel(Boolean.valueOf(additionalProperties.get(PARCELABLE_MODEL).toString()));
}
// put the boolean value back to PARCELABLE_MODEL in additionalProperties
additionalProperties.put(PARCELABLE_MODEL, parcelableModel);
if (additionalProperties.containsKey(USE_BEANVALIDATION)) {
this.setUseBeanValidation(convertPropertyToBooleanAndWriteBack(USE_BEANVALIDATION));
}
if (additionalProperties.containsKey(PERFORM_BEANVALIDATION)) {
this.setPerformBeanValidation(convertPropertyToBooleanAndWriteBack(PERFORM_BEANVALIDATION));
}
if (additionalProperties.containsKey(USE_GZIP_FEATURE)) {
this.setUseGzipFeature(convertPropertyToBooleanAndWriteBack(USE_GZIP_FEATURE));
}
if (additionalProperties.containsKey(USE_RUNTIME_EXCEPTION)) {
this.setUseRuntimeException(convertPropertyToBooleanAndWriteBack(USE_RUNTIME_EXCEPTION));
}
final String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");
final String authFolder = (sourceFolder + '/' + invokerPackage + ".auth").replace(".", "/");
final String apiFolder = (sourceFolder + '/' + apiPackage).replace(".", "/");
//Common files
writeOptional(outputFolder, new SupportingFile("pom.mustache", "", "pom.xml"));
writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md"));
writeOptional(outputFolder, new SupportingFile("build.gradle.mustache", "", "build.gradle"));
writeOptional(outputFolder, new SupportingFile("build.sbt.mustache", "", "build.sbt"));
writeOptional(outputFolder, new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
writeOptional(outputFolder, new SupportingFile("gradle.properties.mustache", "", "gradle.properties"));
writeOptional(outputFolder, new SupportingFile("manifest.mustache", projectFolder, "AndroidManifest.xml"));
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
supportingFiles.add(new SupportingFile("ApiClient.mustache", invokerFolder, "ApiClient.java"));
if (!("resttemplate".equals(getLibrary()) || REST_ASSURED.equals(getLibrary()))) {
supportingFiles.add(new SupportingFile("StringUtil.mustache", invokerFolder, "StringUtil.java"));
}
// google-api-client doesn't use the Swagger auth, because it uses Google Credential directly (HttpRequestInitializer)
if (!("google-api-client".equals(getLibrary()) || REST_ASSURED.equals(getLibrary()))) {
supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java"));
supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java"));
supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java"));
supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java"));
}
supportingFiles.add(new SupportingFile("gradlew.mustache", "", "gradlew"));
supportingFiles.add(new SupportingFile("gradlew.bat.mustache", "", "gradlew.bat"));
supportingFiles.add(new SupportingFile("gradle-wrapper.properties.mustache",
gradleWrapperPackage.replace(".", File.separator), "gradle-wrapper.properties"));
supportingFiles.add(new SupportingFile("gradle-wrapper.jar",
gradleWrapperPackage.replace(".", File.separator), "gradle-wrapper.jar"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
if (performBeanValidation) {
supportingFiles.add(new SupportingFile("BeanValidationException.mustache", invokerFolder,
"BeanValidationException.java"));
}
//TODO: add doc to retrofit1 and feign
if ("feign".equals(getLibrary()) || "retrofit".equals(getLibrary())) {
modelDocTemplateFiles.remove("model_doc.mustache");
apiDocTemplateFiles.remove("api_doc.mustache");
}
if (!("feign".equals(getLibrary()) || "resttemplate".equals(getLibrary()) || usesAnyRetrofitLibrary() || "google-api-client".equals(getLibrary()) || REST_ASSURED.equals(getLibrary()))) {
supportingFiles.add(new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java"));
supportingFiles.add(new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java"));
supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java"));
supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java"));
}
if ("feign".equals(getLibrary())) {
additionalProperties.put("jackson", "true");
supportingFiles.add(new SupportingFile("ParamExpander.mustache", invokerFolder, "ParamExpander.java"));
supportingFiles.add(new SupportingFile("EncodingUtils.mustache", invokerFolder, "EncodingUtils.java"));
} else if ("okhttp-gson".equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) {
// the "okhttp-gson" library template requires "ApiCallback.mustache" for async call
supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java"));
supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java"));
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
supportingFiles.add(new SupportingFile("ProgressRequestBody.mustache", invokerFolder, "ProgressRequestBody.java"));
supportingFiles.add(new SupportingFile("ProgressResponseBody.mustache", invokerFolder, "ProgressResponseBody.java"));
supportingFiles.add(new SupportingFile("GzipRequestInterceptor.mustache", invokerFolder, "GzipRequestInterceptor.java"));
additionalProperties.put("gson", "true");
} else if (usesAnyRetrofitLibrary()) {
supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
supportingFiles.add(new SupportingFile("CollectionFormats.mustache", invokerFolder, "CollectionFormats.java"));
additionalProperties.put("gson", "true");
if ("retrofit2".equals(getLibrary()) && !usePlayWS) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
}
} else if ("jersey2".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java"));
additionalProperties.put("jackson", "true");
} else if ("resteasy".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
additionalProperties.put("jackson", "true");
} else if ("jersey1".equals(getLibrary())) {
additionalProperties.put("jackson", "true");
} else if ("resttemplate".equals(getLibrary())) {
additionalProperties.put("jackson", "true");
supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java"));
} else if ("vertx".equals(getLibrary())) {
typeMapping.put("file", "AsyncFile");
importMapping.put("AsyncFile", "io.vertx.core.file.AsyncFile");
setJava8Mode(true);
additionalProperties.put("java8", "true");
additionalProperties.put("jackson", "true");
apiTemplateFiles.put("apiImpl.mustache", "Impl.java");
apiTemplateFiles.put("rxApiImpl.mustache", ".java");
supportingFiles.remove(new SupportingFile("manifest.mustache", projectFolder, "AndroidManifest.xml"));
} else if ("google-api-client".equals(getLibrary())) {
additionalProperties.put("jackson", "true");
} else if (REST_ASSURED.equals(getLibrary())) {
additionalProperties.put("gson", "true");
apiTemplateFiles.put("api.mustache", ".java");
supportingFiles.add(new SupportingFile("ResponseSpecBuilders.mustache", invokerFolder, "ResponseSpecBuilders.java"));
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
supportingFiles.add(new SupportingFile("GsonObjectMapper.mustache", invokerFolder, "GsonObjectMapper.java"));
} else {
LOGGER.error("Unknown library option (-l/--library): " + getLibrary());
}
if (usePlayWS) {
// remove unsupported auth
Iterator<SupportingFile> iter = supportingFiles.iterator();
while (iter.hasNext()) {
SupportingFile sf = iter.next();
if (sf.templateFile.startsWith("auth/")) {
iter.remove();
}
}
apiTemplateFiles.remove("api.mustache");
if (PLAY_24.equals(playVersion)) {
additionalProperties.put(PLAY_24, true);
apiTemplateFiles.put("play24/api.mustache", ".java");
supportingFiles.add(new SupportingFile("play24/ApiClient.mustache", invokerFolder, "ApiClient.java"));
supportingFiles.add(new SupportingFile("play24/Play24CallFactory.mustache", invokerFolder, "Play24CallFactory.java"));
supportingFiles.add(new SupportingFile("play24/Play24CallAdapterFactory.mustache", invokerFolder,
"Play24CallAdapterFactory.java"));
} else {
additionalProperties.put(PLAY_25, true);
apiTemplateFiles.put("play25/api.mustache", ".java");
supportingFiles.add(new SupportingFile("play25/ApiClient.mustache", invokerFolder, "ApiClient.java"));
supportingFiles.add(new SupportingFile("play25/Play25CallFactory.mustache", invokerFolder, "Play25CallFactory.java"));
supportingFiles.add(new SupportingFile("play25/Play25CallAdapterFactory.mustache", invokerFolder,
"Play25CallAdapterFactory.java"));
additionalProperties.put("java8", "true");
}
supportingFiles.add(new SupportingFile("play-common/auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java"));
supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java"));
supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java"));
additionalProperties.put("jackson", "true");
additionalProperties.remove("gson");
}
if (additionalProperties.containsKey("jackson")) {
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", invokerFolder, "RFC3339DateFormat.java"));
if ("threetenbp".equals(dateLibrary) && !usePlayWS) {
supportingFiles.add(new SupportingFile("CustomInstantDeserializer.mustache", invokerFolder, "CustomInstantDeserializer.java"));
}
}
}
private boolean usesAnyRetrofitLibrary() {
return getLibrary() != null && getLibrary().contains(RETROFIT_1);
}
private boolean usesRetrofit2Library() {
return getLibrary() != null && getLibrary().contains(RETROFIT_2);
}
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
super.postProcessOperations(objs);
if (usesAnyRetrofitLibrary()) {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
if (operations != null) {
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation operation : ops) {
if (operation.hasConsumes == Boolean.TRUE) {
if (isMultipartType(operation.consumes)) {
operation.isMultipart = Boolean.TRUE;
} else {
operation.prioritizedContentTypes = prioritizeContentTypes(operation.consumes);
}
}
if (usesRetrofit2Library() && StringUtils.isNotEmpty(operation.path) && operation.path.startsWith("/")) {
operation.path = operation.path.substring(1);
}
// sorting operation parameters to make sure path params are parsed before query params
if (operation.allParams != null) {
sort(operation.allParams, new Comparator<CodegenParameter>() {
@Override
public int compare(CodegenParameter one, CodegenParameter another) {
if (one.isPathParam && another.isQueryParam) {
return -1;
}
if (one.isQueryParam && another.isPathParam) {
return 1;
}
return 0;
}
});
Iterator<CodegenParameter> iterator = operation.allParams.iterator();
while (iterator.hasNext()) {
CodegenParameter param = iterator.next();
param.hasMore = iterator.hasNext();
}
}
}
}
}
// camelize path variables for Feign client
if ("feign".equals(getLibrary())) {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation op : operationList) {
String path = op.path;
String[] items = path.split("/", -1);
for (int i = 0; i < items.length; ++i) {
if (items[i].matches("^\\{(.*)\\}$")) { // wrap in {}
// camelize path variable
items[i] = "{" + camelize(items[i].substring(1, items[i].length() - 1), true) + "}";
}
}
op.path = StringUtils.join(items, "/");
}
}
return objs;
}
@Override
public String apiFilename(String templateName, String tag) {
if ("vertx".equals(getLibrary())) {
String suffix = apiTemplateFiles().get(templateName);
String subFolder = "";
if (templateName.startsWith("rx")) {
subFolder = "/rxjava";
}
return apiFileFolder() + subFolder + '/' + toApiFilename(tag) + suffix;
} else {
return super.apiFilename(templateName, tag);
}
}
/**
* Prioritizes consumes mime-type list by moving json-vendor and json mime-types up front, but
* otherwise preserves original consumes definition order.
* [application/vnd...+json,... application/json, ..as is..]
*
* @param consumes consumes mime-type list
* @return
*/
static List<Map<String, String>> prioritizeContentTypes(List<Map<String, String>> consumes) {
if (consumes.size() <= 1)
return consumes;
List<Map<String, String>> prioritizedContentTypes = new ArrayList<>(consumes.size());
List<Map<String, String>> jsonVendorMimeTypes = new ArrayList<>(consumes.size());
List<Map<String, String>> jsonMimeTypes = new ArrayList<>(consumes.size());
for (Map<String, String> consume : consumes) {
if (isJsonVendorMimeType(consume.get(MEDIA_TYPE))) {
jsonVendorMimeTypes.add(consume);
} else if (isJsonMimeType(consume.get(MEDIA_TYPE))) {
jsonMimeTypes.add(consume);
} else
prioritizedContentTypes.add(consume);
consume.put("hasMore", "true");
}
prioritizedContentTypes.addAll(0, jsonMimeTypes);
prioritizedContentTypes.addAll(0, jsonVendorMimeTypes);
prioritizedContentTypes.get(prioritizedContentTypes.size() - 1).put("hasMore", null);
return prioritizedContentTypes;
}
private static boolean isMultipartType(List<Map<String, String>> consumes) {
Map<String, String> firstType = consumes.get(0);
if (firstType != null) {
if ("multipart/form-data".equals(firstType.get(MEDIA_TYPE))) {
return true;
}
}
return false;
}
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
super.postProcessModelProperty(model, property);
if (!BooleanUtils.toBoolean(model.isEnum)) {
//final String lib = getLibrary();
//Needed imports for Jackson based libraries
if (additionalProperties.containsKey("jackson")) {
model.imports.add("JsonProperty");
model.imports.add("JsonValue");
}
if (additionalProperties.containsKey("gson")) {
model.imports.add("SerializedName");
model.imports.add("TypeAdapter");
model.imports.add("JsonAdapter");
model.imports.add("JsonReader");
model.imports.add("JsonWriter");
model.imports.add("IOException");
}
} else { // enum class
//Needed imports for Jackson's JsonCreator
if (additionalProperties.containsKey("jackson")) {
model.imports.add("JsonValue");
model.imports.add("JsonCreator");
}
}
}
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
Map<String, Object> allProcessedModels = super.postProcessAllModels(objs);
if (!additionalProperties.containsKey("gsonFactoryMethod")) {
List<Object> allModels = new ArrayList<Object>();
for (String name : allProcessedModels.keySet()) {
Map<String, Object> models = (Map<String, Object>) allProcessedModels.get(name);
try {
allModels.add(((List<Object>) models.get("models")).get(0));
} catch (Exception e) {
e.printStackTrace();
}
}
additionalProperties.put("parent", modelInheritanceSupportInGson(allModels));
}
return allProcessedModels;
}
@Override
public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
objs = super.postProcessModelsEnum(objs);
//Needed import for Gson based libraries
if (additionalProperties.containsKey("gson")) {
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
List<Object> models = (List<Object>) objs.get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
// for enum model
if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) {
cm.imports.add(importMapping.get("SerializedName"));
Map<String, String> item = new HashMap<String, String>();
item.put("import", importMapping.get("SerializedName"));
imports.add(item);
}
}
}
return objs;
}
private List<Map<String, Object>> modelInheritanceSupportInGson(List<?> allModels) {
LinkedListMultimap<CodegenModel, CodegenModel> byParent = LinkedListMultimap.create();
for (Object m : allModels) {
Map entry = (Map) m;
CodegenModel parent = ((CodegenModel) entry.get("model")).parentModel;
if (null != parent) {
byParent.put(parent, ((CodegenModel) entry.get("model")));
}
}
List<Map<String, Object>> parentsList = new ArrayList<>();
for (CodegenModel parentModel : byParent.keySet()) {
List<Map<String, Object>> childrenList = new ArrayList<>();
Map<String, Object> parent = new HashMap<>();
parent.put("classname", parentModel.classname);
List<CodegenModel> childrenModels = byParent.get(parentModel);
for (CodegenModel model : childrenModels) {
Map<String, Object> child = new HashMap<>();
child.put("name", model.name);
child.put("classname", model.classname);
childrenList.add(child);
}
parent.put("children", childrenList);
parent.put("discriminator", parentModel.discriminator);
parentsList.add(parent);
}
return parentsList;
}
public void setUseRxJava(boolean useRxJava) {
this.useRxJava = useRxJava;
doNotUseRx = false;
}
public void setUseRxJava2(boolean useRxJava2) {
this.useRxJava2 = useRxJava2;
doNotUseRx = false;
}
public void setDoNotUseRx(boolean doNotUseRx) {
this.doNotUseRx = doNotUseRx;
}
public void setUsePlayWS(boolean usePlayWS) {
this.usePlayWS = usePlayWS;
}
public void setPlayVersion(String playVersion) {
this.playVersion = playVersion;
}
public void setParcelableModel(boolean parcelableModel) {
this.parcelableModel = parcelableModel;
}
public void setUseBeanValidation(boolean useBeanValidation) {
this.useBeanValidation = useBeanValidation;
}
public void setPerformBeanValidation(boolean performBeanValidation) {
this.performBeanValidation = performBeanValidation;
}
public void setUseGzipFeature(boolean useGzipFeature) {
this.useGzipFeature = useGzipFeature;
}
public void setUseRuntimeException(boolean useRuntimeException) {
this.useRuntimeException = useRuntimeException;
}
final private static Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)application\\/json(;.*)?");
final private static Pattern JSON_VENDOR_MIME_PATTERN = Pattern.compile("(?i)application\\/vnd.(.*)+json(;.*)?");
/**
* Check if the given MIME is a JSON MIME.
* JSON MIME examples:
* application/json
* application/json; charset=UTF8
* APPLICATION/JSON
*/
static boolean isJsonMimeType(String mime) {
return mime != null && (JSON_MIME_PATTERN.matcher(mime).matches());
}
/**
* Check if the given MIME is a JSON Vendor MIME.
* JSON MIME examples:
* application/vnd.mycompany+json
* application/vnd.mycompany.resourceA.version1+json
*/
static boolean isJsonVendorMimeType(String mime) {
return mime != null && JSON_VENDOR_MIME_PATTERN.matcher(mime).matches();
}
}

View File

@@ -0,0 +1,11 @@
package org.openapitools.codegen.languages.features;
public interface BeanValidationExtendedFeatures {
// Language (implementing Client/Server) supports automatic BeanValidation (1.1)
public static final String USE_BEANVALIDATION_FEATURE = "useBeanValidationFeature";
public void setUseBeanValidationFeature(boolean useBeanValidationFeature);
}

View File

@@ -0,0 +1,10 @@
package org.openapitools.codegen.languages.features;
public interface BeanValidationFeatures {
// Language supports generating BeanValidation-Annotations
public static final String USE_BEANVALIDATION = "useBeanValidation";
public void setUseBeanValidation(boolean useBeanValidation);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
/**
* Features supported by CXF 3 (client + server)
*/
public interface CXFFeatures extends LoggingFeatures, GzipFeatures, BeanValidationFeatures {
}

View File

@@ -0,0 +1,29 @@
package org.openapitools.codegen.languages.features;
/**
* Features supported by CXF 3 server
*/
public interface CXFServerFeatures
extends CXFFeatures, SwaggerFeatures, SpringFeatures, JbossFeature, BeanValidationExtendedFeatures, SwaggerUIFeatures {
public static final String USE_WADL_FEATURE = "useWadlFeature";
public static final String USE_MULTIPART_FEATURE = "useMultipartFeature";
public static final String ADD_CONSUMES_PRODUCES_JSON = "addConsumesProducesJson";
public static final String USE_ANNOTATED_BASE_PATH = "useAnnotatedBasePath";
public static final String GENERATE_NON_SPRING_APPLICATION = "generateNonSpringApplication";
public void setUseWadlFeature(boolean useWadlFeature);
public void setUseMultipartFeature(boolean useMultipartFeature);
public void setAddConsumesProducesJson(boolean addConsumesProducesJson);
public void setUseAnnotatedBasePath(boolean useAnnotatedBasePath);
public void setGenerateNonSpringApplication(boolean generateNonSpringApplication);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
public interface GzipFeatures {
public static final String USE_GZIP_FEATURE = "useGzipFeature";
public void setUseGzipFeature(boolean useGzipFeature);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
public interface GzipTestFeatures {
public static final String USE_GZIP_FEATURE_FOR_TESTS = "useGzipFeatureForTests";
public void setUseGzipFeatureForTests(boolean useGzipFeatureForTests);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
public interface JbossFeature {
public static final String GENERATE_JBOSS_DEPLOYMENT_DESCRIPTOR = "generateJbossDeploymentDescriptor";
public void setGenerateJbossDeploymentDescriptor(boolean generateJbossDeploymentDescriptor);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
public interface LoggingFeatures extends BeanValidationFeatures {
public static final String USE_LOGGING_FEATURE = "useLoggingFeature";
public void setUseLoggingFeature(boolean useLoggingFeature);
}

View File

@@ -0,0 +1,8 @@
package org.openapitools.codegen.languages.features;
public interface LoggingTestFeatures {
public static final String USE_LOGGING_FEATURE_FOR_TESTS = "useLoggingFeatureForTests";
public void setUseLoggingFeatureForTests(boolean useLoggingFeatureForTests);
}

View File

@@ -0,0 +1,10 @@
package org.openapitools.codegen.languages.features;
public interface OptionalFeatures {
// Language supports generating Optional Types
String USE_OPTIONAL = "useOptional";
void setUseOptional(boolean useOptional);
}

View File

@@ -0,0 +1,10 @@
package org.openapitools.codegen.languages.features;
public interface PerformBeanValidationFeatures {
// Language supports performing BeanValidation
public static final String PERFORM_BEANVALIDATION = "performBeanValidation";
public void setPerformBeanValidation(boolean performBeanValidation);
}

View File

@@ -0,0 +1,18 @@
package org.openapitools.codegen.languages.features;
public interface SpringFeatures extends BeanValidationFeatures {
public static final String GENERATE_SPRING_APPLICATION = "generateSpringApplication";
public static final String GENERATE_SPRING_BOOT_APPLICATION = "generateSpringBootApplication";
public static final String USE_SPRING_ANNOTATION_CONFIG = "useSpringAnnotationConfig";
public void setGenerateSpringApplication(boolean useGenerateSpringApplication);
public void setGenerateSpringBootApplication(boolean generateSpringBootApplication);
public void setUseSpringAnnotationConfig(boolean useSpringAnnotationConfig);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
public interface SwaggerFeatures {
public static final String USE_SWAGGER_FEATURE = "useSwaggerFeature";
public void setUseSwaggerFeature(boolean useSwaggerFeature);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
public interface SwaggerUIFeatures extends CXFFeatures {
public static final String USE_SWAGGER_UI = "useSwaggerUI";
public void setUseSwaggerUI(boolean useSwaggerUI);
}

View File

@@ -0,0 +1,9 @@
package org.openapitools.codegen.languages.features;
public interface UseGenericResponseFeatures {
// Language supports generating generic Jaxrs or native return types
public static final String USE_GENERIC_RESPONSE = "useGenericResponse";
public void setUseGenericResponse(boolean useGenericResponse);
}

View File

@@ -30,6 +30,7 @@ org.openapitools.codegen.languages.KotlinClientCodegen
org.openapitools.codegen.languages.KotlinServerCodegen
org.openapitools.codegen.languages.HaskellHttpClientCodegen
org.openapitools.codegen.languages.HaskellServantCodegen
org.openapitools.codegen.languages.JavaClientCodegen
org.openapitools.codegen.languages.JavascriptClientCodegen
org.openapitools.codegen.languages.JavascriptClosureAngularClientCodegen
org.openapitools.codegen.languages.LuaClientCodegen