Adapt output path for api/model

This commit is contained in:
Johannes Fiala
2015-12-05 17:35:18 +01:00
parent 9367b7f6a6
commit 7c4471a4d6
17 changed files with 2019 additions and 0 deletions

View File

@@ -0,0 +1,599 @@
package io.swagger.codegen.languages;
import com.google.common.base.Strings;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.CodegenConstants;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenOperation;
import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.DefaultCodegen;
import io.swagger.codegen.SupportingFile;
import io.swagger.models.Model;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.LongProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.RefProperty;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JavascriptClientCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(JavascriptClientCodegen.class);
protected String invokerPackage = "io.swagger.client";
protected String groupId = "io.swagger";
protected String artifactId = "swagger-java-client";
protected String artifactVersion = "1.0.0";
protected String sourceFolder = "src";
protected String localVariablePrefix = "";
protected boolean fullJavaUtil = false;
protected String javaUtilPrefix = "";
protected Boolean serializableModel = false;
public JavascriptClientCodegen() {
super();
outputFolder = "generated-code/js";
modelTemplateFiles.put("model.mustache", ".js");
apiTemplateFiles.put("api.mustache", ".js");
templateDir = "Javascript";
apiPackage = "api";
modelPackage = "model";
reservedWords = new HashSet<String>(
Arrays.asList(
"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")
);
languageSpecificPrimitives = new HashSet<String>(
Arrays.asList(
"String",
"boolean",
"Boolean",
"Double",
"Integer",
"Long",
"Float",
"Object",
"byte[]")
);
instantiationTypes.put("array", "ArrayList");
instantiationTypes.put("map", "HashMap");
cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC));
cliOptions.add(new CliOption(CodegenConstants.GROUP_ID, CodegenConstants.GROUP_ID_DESC));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_ID, CodegenConstants.ARTIFACT_ID_DESC));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC));
cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC));
cliOptions.add(new CliOption(CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC));
cliOptions.add(new CliOption(CodegenConstants.SERIALIZABLE_MODEL, CodegenConstants.SERIALIZABLE_MODEL_DESC));
cliOptions.add(new CliOption("fullJavaUtil", "whether to use fully qualified name for classes under java.util (default to false)"));
/*
supportedLibraries.put("<default>", "HTTP client: Jersey client 1.18. JSON processing: Jackson 2.4.2");
supportedLibraries.put("jersey2", "HTTP client: Jersey client 2.6");
supportedLibraries.put("okhttp-gson", "HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1");
supportedLibraries.put("retrofit", "HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1 (Retrofit 1.9.0)");
cliOptions.add(buildLibraryCliOption(supportedLibraries));*/
}
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "javascript";
}
@Override
public String getHelp() {
return "Generates a Javascript client library.";
}
@Override
public void processOpts() {
super.processOpts();
/*
if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
} else {
//not set, use default to be passed to template
additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
}
if (additionalProperties.containsKey(CodegenConstants.GROUP_ID)) {
this.setGroupId((String) additionalProperties.get(CodegenConstants.GROUP_ID));
} else {
//not set, use to be passed to template
additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
}
if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_ID)) {
this.setArtifactId((String) additionalProperties.get(CodegenConstants.ARTIFACT_ID));
} else {
//not set, use to be passed to template
additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
}
if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_VERSION)) {
this.setArtifactVersion((String) additionalProperties.get(CodegenConstants.ARTIFACT_VERSION));
} else {
//not set, use to be passed to template
additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
}
if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
this.setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER));
}
if (additionalProperties.containsKey(CodegenConstants.LOCAL_VARIABLE_PREFIX)) {
this.setLocalVariablePrefix((String) additionalProperties.get(CodegenConstants.LOCAL_VARIABLE_PREFIX));
}
if (additionalProperties.containsKey(CodegenConstants.SERIALIZABLE_MODEL)) {
this.setSerializableModel(Boolean.valueOf((String)additionalProperties.get(CodegenConstants.SERIALIZABLE_MODEL).toString()));
}
if (additionalProperties.containsKey(CodegenConstants.LIBRARY)) {
this.setLibrary((String) additionalProperties.get(CodegenConstants.LIBRARY));
}
// need to put back serializableModel (boolean) into additionalProperties as value in additionalProperties is string
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, serializableModel);
if (additionalProperties.containsKey("fullJavaUtil")) {
fullJavaUtil = Boolean.valueOf(additionalProperties.get("fullJavaUtil").toString());
}
if (fullJavaUtil) {
javaUtilPrefix = "java.util.";
}
additionalProperties.put("fullJavaUtil", fullJavaUtil);
additionalProperties.put("javaUtilPrefix", javaUtilPrefix);
if (fullJavaUtil) {
typeMapping.put("array", "java.util.List");
typeMapping.put("map", "java.util.Map");
typeMapping.put("DateTime", "java.util.Date");
typeMapping.remove("List");
importMapping.remove("Date");
importMapping.remove("Map");
importMapping.remove("HashMap");
importMapping.remove("Array");
importMapping.remove("ArrayList");
importMapping.remove("List");
importMapping.remove("Set");
importMapping.remove("DateTime");
instantiationTypes.put("array", "java.util.ArrayList");
instantiationTypes.put("map", "java.util.HashMap");
}
this.sanitizeConfig();
final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator);
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
supportingFiles.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
supportingFiles.add(new SupportingFile("gradle.properties.mustache", "", "gradle.properties"));
supportingFiles.add(new SupportingFile("ApiClient.mustache", invokerFolder, "ApiClient.java"));
supportingFiles.add(new SupportingFile("StringUtil.mustache", invokerFolder, "StringUtil.java"));
final String authFolder = (sourceFolder + File.separator + invokerPackage + ".auth").replace(".", File.separator);
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"));
if (!"retrofit".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java"));
supportingFiles.add(new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java"));
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java"));
supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java"));
}
// library-specific files
if ("okhttp-gson".equals(getLibrary())) {
// the "okhttp-gson" library template requires "ApiCallback.mustache" for async call
supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java"));
// "build.sbt" is for development with SBT
supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
} else if ("retrofit".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
supportingFiles.add(new SupportingFile("CollectionFormats.mustache", invokerFolder, "CollectionFormats.java"));
} else {
supportingFiles.add(new SupportingFile("TypeRef.mustache", invokerFolder, "TypeRef.java"));
}*/
}
/*
private void sanitizeConfig() {
// Sanitize any config options here. We also have to update the additionalProperties because
// the whole additionalProperties object is injected into the main object passed to the mustache layer
this.setApiPackage(sanitizePackageName(apiPackage));
if (additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
this.additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
}
this.setModelPackage(sanitizePackageName(modelPackage));
if (additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) {
this.additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
}
this.setInvokerPackage(sanitizePackageName(invokerPackage));
if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
}
}*/
@Override
public String escapeReservedWord(String name) {
return "_" + name;
}
@Override
public String apiFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar);
}
@Override
public String modelFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar);
}
@Override
public String toVarName(String name) {
// sanitize name
name = sanitizeName(name);
if("_".equals(name)) {
name = "_u";
}
// if it's all uppper case, do nothing
if (name.matches("^[A-Z_]*$")) {
return name;
}
// camelize (lower first character) the variable name
// pet_id => petId
name = camelize(name, true);
// for reserved word or word starting with number, append _
if (reservedWords.contains(name) || name.matches("^\\d.*")) {
name = escapeReservedWord(name);
}
return name;
}
@Override
public String toParamName(String name) {
// should be the same as variable name
return toVarName(name);
}
@Override
public String toModelName(String name) {
name = sanitizeName(name);
// model name cannot use reserved keyword, e.g. return
if (reservedWords.contains(name)) {
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");
}
// camelize the model name
// phone_number => PhoneNumber
return camelize(name);
}
@Override
public String toModelFilename(String name) {
// should be the same as the model name
return toModelName(name);
}
@Override
public String getTypeDeclaration(Property p) {
if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
Property inner = ap.getItems();
return getSwaggerType(p) + "<" + getTypeDeclaration(inner) + ">";
} else if (p instanceof MapProperty) {
MapProperty mp = (MapProperty) p;
Property inner = mp.getAdditionalProperties();
return getSwaggerType(p) + "<String, " + getTypeDeclaration(inner) + ">";
}
return super.getTypeDeclaration(p);
}
@Override
public String toDefaultValue(Property p) {
if (p instanceof ArrayProperty) {
final ArrayProperty ap = (ArrayProperty) p;
final String pattern;
if (fullJavaUtil) {
pattern = "new java.util.ArrayList<%s>()";
} else {
pattern = "new ArrayList<%s>()";
}
return String.format(pattern, getTypeDeclaration(ap.getItems()));
} else if (p instanceof MapProperty) {
final MapProperty ap = (MapProperty) p;
final String pattern;
if (fullJavaUtil) {
pattern = "new java.util.HashMap<String, %s>()";
} else {
pattern = "new HashMap<String, %s>()";
}
return String.format(pattern, getTypeDeclaration(ap.getAdditionalProperties()));
} else if (p instanceof LongProperty) {
LongProperty dp = (LongProperty) p;
if (dp.getDefault() != null) {
return dp.getDefault().toString()+"l";
}
return "null";
// added for Javascript
} else if (p instanceof RefProperty) {
RefProperty rp = (RefProperty)p;
System.out.println("rp: " + rp.getName() + rp.getAccess() + rp.getDescription() + rp.getExample() + rp.getFormat() + rp.getSimpleRef() + rp.getTitle() + rp.getType());
return "new " +rp.getSimpleRef() + "()";
}
System.out.println("property: " + p);
return super.toDefaultValue(p);
}
@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if (typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if (languageSpecificPrimitives.contains(type) || type.indexOf(".") >= 0) {
return type;
}
} else {
type = swaggerType;
}
if (null == type) {
LOGGER.error("No Type defined for Property " + p);
}
return toModelName(type);
}
@Override
public String toOperationId(String operationId) {
// throw exception if method name is empty
if (StringUtils.isEmpty(operationId)) {
throw new RuntimeException("Empty method/operation name (operationId) not allowed");
}
// method name cannot use reserved keyword, e.g. return
if (reservedWords.contains(operationId)) {
throw new RuntimeException(operationId + " (reserved word) cannot be used as method name");
}
return camelize(sanitizeName(operationId), true);
}
@Override
public CodegenModel fromModel(String name, Model model, Map<String, Model> allDefinitions) {
CodegenModel codegenModel = super.fromModel(name, model, allDefinitions);
if (allDefinitions != null && codegenModel != null && codegenModel.parent != null && codegenModel.hasEnums) {
final Model parentModel = allDefinitions.get(toModelName(codegenModel.parent));
final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel);
}
return codegenModel;
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
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 (CodegenProperty var : cm.vars) {
Map<String, Object> allowableValues = var.allowableValues;
// handle ArrayProperty
if (var.items != null) {
allowableValues = var.items.allowableValues;
}
if (allowableValues == null) {
continue;
}
List<String> values = (List<String>) allowableValues.get("values");
if (values == null) {
continue;
}
// put "enumVars" map into `allowableValues", including `name` and `value`
List<Map<String, String>> enumVars = new ArrayList<Map<String, String>>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (String value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
String enumName;
if (truncateIdx == 0) {
enumName = value;
} else {
enumName = value.substring(truncateIdx);
if ("".equals(enumName)) {
enumName = value;
}
}
enumVar.put("name", toEnumVarName(enumName));
enumVar.put("value", value);
enumVars.add(enumVar);
}
allowableValues.put("enumVars", enumVars);
}
}
return objs;
}
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
if("retrofit".equals(getLibrary())) {
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) {
Map<String, String> firstType = operation.consumes.get(0);
if (firstType != null) {
if ("multipart/form-data".equals(firstType.get("mediaType"))) {
operation.isMultipart = Boolean.TRUE;
}
}
}
if (operation.returnType == null) {
operation.returnType = "Void";
}
}
}
}
return objs;
}
protected boolean needToImport(String type) {
return super.needToImport(type) && type.indexOf(".") < 0;
}
private String findCommonPrefixOfVars(List<String> vars) {
String prefix = StringUtils.getCommonPrefix(vars.toArray(new String[vars.size()]));
// exclude trailing characters that should be part of a valid variable
// e.g. ["status-on", "status-off"] => "status-" (not "status-o")
return prefix.replaceAll("[a-zA-Z0-9]+\\z", "");
}
private String toEnumVarName(String value) {
String var = value.replaceAll("\\W+", "_").toUpperCase();
if (var.matches("\\d.*")) {
return "_" + var;
} else {
return var;
}
}
private CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenModel parentCodegenModel) {
// This generator uses inline classes to define enums, which breaks when
// dealing with models that have subTypes. To clean this up, we will analyze
// the parent and child models, look for enums that match, and remove
// them from the child models and leave them in the parent.
// 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) {
// Get the properties for the parent and child models
final List<CodegenProperty> parentModelCodegenProperties = parentCodegenModel.vars;
List<CodegenProperty> codegenProperties = codegenModel.vars;
// Iterate over all of the parent model properties
boolean removedChildEnum = false;
for (CodegenProperty parentModelCodegenPropery : parentModelCodegenProperties) {
// Look for enums
if (parentModelCodegenPropery.isEnum) {
// Now that we have found an enum in the parent class,
// and search the child class for the same enum.
Iterator<CodegenProperty> iterator = codegenProperties.iterator();
while (iterator.hasNext()) {
CodegenProperty codegenProperty = iterator.next();
if (codegenProperty.isEnum && codegenProperty.equals(parentModelCodegenPropery)) {
// We found an enum in the child class that is
// a duplicate of the one in the parent, so remove it.
iterator.remove();
removedChildEnum = true;
}
}
}
}
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) {
count += 1;
codegenProperty.hasMore = (count < numVars) ? true : null;
}
codegenModel.vars = codegenProperties;
}
}
return codegenModel;
}
public void setInvokerPackage(String invokerPackage) {
this.invokerPackage = invokerPackage;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public void setArtifactId(String artifactId) {
this.artifactId = artifactId;
}
public void setArtifactVersion(String artifactVersion) {
this.artifactVersion = artifactVersion;
}
public void setSourceFolder(String sourceFolder) {
this.sourceFolder = sourceFolder;
}
public void setLocalVariablePrefix(String localVariablePrefix) {
this.localVariablePrefix = localVariablePrefix;
}
public Boolean getSerializableModel() {
return serializableModel;
}
public void setSerializableModel(Boolean serializableModel) {
this.serializableModel = serializableModel;
}
private String sanitizePackageName(String packageName) {
packageName = packageName.trim();
packageName = packageName.replaceAll("[^a-zA-Z0-9_\\.]", "_");
if(Strings.isNullOrEmpty(packageName)) {
return "invalidPackageName";
}
return packageName;
}
}