Merge branches 'develop_2.0' and 'jaxrs-interface-generation' of https://github.com/swagger-api/swagger-codegen into jaxrs-interface-generation

Conflicts:
	modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java
This commit is contained in:
Ole Lensmar
2015-05-20 22:51:49 -06:00
129 changed files with 6774 additions and 23 deletions

View File

@@ -11,6 +11,6 @@ public class CodegenModel {
public String defaultValue;
public List<CodegenProperty> vars = new ArrayList<CodegenProperty>();
public Set<String> imports = new HashSet<String>();
public Boolean hasVars, emptyVars, hasMoreModels;
public Boolean hasVars, emptyVars, hasMoreModels, hasEnums;
public ExternalDocs externalDocs;
}

View File

@@ -8,10 +8,12 @@ public class CodegenResponse {
public List<Map<String, String>> examples;
public final List<CodegenProperty> headers = new ArrayList<CodegenProperty>();
public String dataType, baseType, containerType;
public Boolean isDefault;
public Boolean simpleType;
public Boolean primitiveType;
public Boolean isMapContainer;
public Boolean isListContainer;
public Object schema;
public String jsonSchema;
public boolean isWildcard() { return "0".equals(code) || "default".equals(code); }
}

View File

@@ -1,11 +1,10 @@
package com.wordnik.swagger.codegen;
public class CodegenSecurity {
String name;
String type;
Boolean hasMore, isBasic, isOAuth, isApiKey;
public String name;
public String type;
public Boolean hasMore, isBasic, isOAuth, isApiKey;
// ApiKey specific
String keyParamName;
Boolean isKeyInQuery, isKeyInHeader;
public String keyParamName;
public Boolean isKeyInQuery, isKeyInHeader;
}

View File

@@ -166,6 +166,9 @@ public class DefaultCodegen {
return name;
}
public String toEnumName(CodegenProperty property) {
return StringUtils.capitalize(property.name) + "Enum";
}
public String escapeReservedWord(String name) {
throw new RuntimeException("reserved word " + name + " not allowed");
@@ -470,6 +473,7 @@ public class DefaultCodegen {
}
if(impl.getProperties() != null && impl.getProperties().size() > 0) {
m.hasVars = true;
m.hasEnums = false;
for(String key: impl.getProperties().keySet()) {
Property prop = impl.getProperties().get(key);
@@ -497,6 +501,8 @@ public class DefaultCodegen {
}
m.vars.add(cp);
count += 1;
if (cp.isEnum)
m.hasEnums = true;
if(count != impl.getProperties().keySet().size())
cp.hasMore = new Boolean(true);
if(cp.isContainer != null) {
@@ -589,7 +595,7 @@ public class DefaultCodegen {
// this can cause issues for clients which don't support enums
if(property.isEnum)
property.datatypeWithEnum = StringUtils.capitalize(property.name) + "Enum";
property.datatypeWithEnum = toEnumName(property);
else
property.datatypeWithEnum = property.datatype;
@@ -722,7 +728,6 @@ public class DefaultCodegen {
if (operation.getResponses() != null && !operation.getResponses().isEmpty()) {
Response methodResponse = findMethodResponse(operation.getResponses());
CodegenResponse methodCodegenResponse = null;
for (Map.Entry<String, Response> entry : operation.getResponses().entrySet()) {
Response response = entry.getValue();
@@ -732,9 +737,7 @@ public class DefaultCodegen {
!defaultIncludes.contains(r.baseType) &&
!languageSpecificPrimitives.contains(r.baseType))
imports.add(r.baseType);
if (response == methodResponse)
methodCodegenResponse = r;
r.isDefault = response == methodResponse;
op.responses.add(r);
}
op.responses.get(op.responses.size() - 1).hasMore = false;
@@ -918,6 +921,19 @@ public class DefaultCodegen {
collectionFormat = qp.getCollectionFormat();
CodegenProperty pr = fromProperty("inner", inner);
p.baseType = pr.datatype;
p.isContainer = true;
imports.add(pr.baseType);
}
else if("object".equals(qp.getType())) {
Property inner = qp.getItems();
if(inner == null) {
LOGGER.warn("warning! No inner type supplied for map parameter \"" + qp.getName() + "\", using String");
inner = new StringProperty().description("//TODO automatically added by swagger-codegen");
}
property = new MapProperty(inner);
collectionFormat = qp.getCollectionFormat();
CodegenProperty pr = fromProperty("inner", inner);
p.baseType = pr.datatype;
imports.add(pr.baseType);
}
else
@@ -926,6 +942,7 @@ public class DefaultCodegen {
LOGGER.warn("warning! Property type \"" + qp.getType() + "\" not found for parameter \"" + param.getName() + "\", using String");
property = new StringProperty().description("//TODO automatically added by swagger-codegen. Type was " + qp.getType() + " but not supported");
}
property.setRequired(param.getRequired());
CodegenProperty model = fromProperty(qp.getName(), property);
p.collectionFormat = collectionFormat;
p.dataType = model.datatype;
@@ -949,6 +966,7 @@ public class DefaultCodegen {
else {
// TODO: missing format, so this will not always work
Property prop = PropertyBuilder.build(impl.getType(), null, null);
prop.setRequired(bp.getRequired());
CodegenProperty cp = fromProperty("property", prop);
if(cp != null) {
p.dataType = cp.datatype;
@@ -962,6 +980,7 @@ public class DefaultCodegen {
CodegenModel cm = fromModel(bp.getName(), impl);
// get the single property
ArrayProperty ap = new ArrayProperty().items(impl.getItems());
ap.setRequired(param.getRequired());
CodegenProperty cp = fromProperty("inner", ap);
if(cp.complexType != null) {
imports.add(cp.complexType);

View File

@@ -0,0 +1,365 @@
package com.wordnik.swagger.codegen.languages;
import com.google.common.base.CaseFormat;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import com.wordnik.swagger.codegen.*;
import com.wordnik.swagger.models.auth.SecuritySchemeDefinition;
import com.wordnik.swagger.models.properties.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.*;
public class AkkaScalaClientCodegen extends DefaultCodegen implements CodegenConfig {
Logger LOGGER = LoggerFactory.getLogger(AkkaScalaClientCodegen.class);
protected String mainPackage = "io.swagger.client";
protected String invokerPackage = mainPackage + ".core";
protected String groupId = "com.wordnik";
protected String artifactId = "swagger-client";
protected String artifactVersion = "1.0.0";
protected String sourceFolder = "src/main/scala";
protected String resourcesFolder = "src/main/resources";
protected String configKey = "apiRequest";
protected int defaultTimeoutInMs = 5000;
protected String configKeyPath = mainPackage;
protected boolean registerNonStandardStatusCodes = true;
protected boolean renderJavadoc = true;
protected boolean removeOAuthSecurities = true;
/**
* If set to true, only the default response (the one with le lowest 2XX code) will be considered as a success, and all
* others as ApiErrors.
* If set to false, all responses defined in the model will be considered as a success upon reception. Only http errors,
* unmarshalling problems and any other RuntimeException will be considered as ApiErrors.
*/
protected boolean onlyOneSuccess = true;
public CodegenType getTag() {
return CodegenType.CLIENT;
}
public String getName() {
return "akka-scala";
}
public String getHelp() {
return "Generates a Scala client library base on Akka/Spray.";
}
public AkkaScalaClientCodegen() {
super();
outputFolder = "generated-code/scala";
modelTemplateFiles.put("model.mustache", ".scala");
apiTemplateFiles.put("api.mustache", ".scala");
templateDir = "akka-scala";
apiPackage = mainPackage + ".api";
modelPackage = mainPackage + ".model";
reservedWords = new HashSet<String>(
Arrays.asList(
"abstract", "case", "catch", "class", "def", "do", "else", "extends",
"false", "final", "finally", "for", "forSome", "if", "implicit",
"import", "lazy", "match", "new", "null", "object", "override", "package",
"private", "protected", "return", "sealed", "super", "this", "throw",
"trait", "try", "true", "type", "val", "var", "while", "with", "yield")
);
additionalProperties.put("invokerPackage", invokerPackage);
additionalProperties.put("groupId", groupId);
additionalProperties.put("artifactId", artifactId);
additionalProperties.put("artifactVersion", artifactVersion);
additionalProperties.put("configKey", configKey);
additionalProperties.put("configKeyPath", configKeyPath);
additionalProperties.put("defaultTimeout", defaultTimeoutInMs);
if (renderJavadoc)
additionalProperties.put("javadocRenderer", new JavadocLambda());
additionalProperties.put("fnCapitalize", new CapitalizeLambda());
additionalProperties.put("fnCamelize", new CamelizeLambda(false));
additionalProperties.put("fnEnumEntry", new EnumEntryLambda());
additionalProperties.put("onlyOneSuccess", onlyOneSuccess);
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
supportingFiles.add(new SupportingFile("reference.mustache", resourcesFolder, "reference.conf"));
final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator);
supportingFiles.add(new SupportingFile("apiRequest.mustache", invokerFolder, "ApiRequest.scala"));
supportingFiles.add(new SupportingFile("apiInvoker.mustache", invokerFolder, "ApiInvoker.scala"));
supportingFiles.add(new SupportingFile("requests.mustache", invokerFolder, "requests.scala"));
supportingFiles.add(new SupportingFile("apiSettings.mustache", invokerFolder, "ApiSettings.scala"));
final String apiFolder = (sourceFolder + File.separator + apiPackage).replace(".", File.separator);
supportingFiles.add(new SupportingFile("enumsSerializers.mustache", apiFolder, "EnumsSerializers.scala"));
importMapping.remove("Seq");
importMapping.remove("List");
importMapping.remove("Set");
importMapping.remove("Map");
importMapping.put("DateTime", "org.joda.time.DateTime");
typeMapping = new HashMap<String, String>();
typeMapping.put("array", "Seq");
typeMapping.put("set", "Set");
typeMapping.put("boolean", "Boolean");
typeMapping.put("string", "String");
typeMapping.put("int", "Int");
typeMapping.put("integer", "Int");
typeMapping.put("long", "Long");
typeMapping.put("float", "Float");
typeMapping.put("byte", "Byte");
typeMapping.put("short", "Short");
typeMapping.put("char", "Char");
typeMapping.put("long", "Long");
typeMapping.put("double", "Double");
typeMapping.put("object", "Any");
typeMapping.put("file", "File");
typeMapping.put("number", "Double");
languageSpecificPrimitives = new HashSet<String>(
Arrays.asList(
"String",
"boolean",
"Boolean",
"Double",
"Int",
"Long",
"Float",
"Object",
"List",
"Seq",
"Map")
);
instantiationTypes.put("array", "ListBuffer");
instantiationTypes.put("map", "Map");
}
@Override
public String escapeReservedWord(String name) {
return "`" + name + "`";
}
@Override
public String apiFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar);
}
public String modelFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar);
}
@Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
if (registerNonStandardStatusCodes) {
try {
@SuppressWarnings("unchecked")
Map<String, ArrayList<CodegenOperation>> opsMap = (Map<String, ArrayList<CodegenOperation>>) objs.get("operations");
HashSet<Integer> unknownCodes = new HashSet<Integer>();
for (CodegenOperation operation : opsMap.get("operation")) {
for (CodegenResponse response : operation.responses) {
if ("default".equals(response.code))
continue;
try {
int code = Integer.parseInt(response.code);
if (code >= 600) {
unknownCodes.add(code);
}
} catch (NumberFormatException e) {
LOGGER.error("Status code is not an integer : response.code", e);
}
}
}
if (!unknownCodes.isEmpty()) {
additionalProperties.put("unknownStatusCodes", unknownCodes);
}
} catch (Exception e) {
LOGGER.error("Unable to find operations List", e);
}
}
return super.postProcessOperations(objs);
}
@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 List<CodegenSecurity> fromSecurity(Map<String, SecuritySchemeDefinition> schemes) {
final List<CodegenSecurity> codegenSecurities = super.fromSecurity(schemes);
if (!removeOAuthSecurities)
return codegenSecurities;
// Remove OAuth securities
Iterator<CodegenSecurity> it = codegenSecurities.iterator();
while (it.hasNext()) {
final CodegenSecurity security = it.next();
if (security.isOAuth)
it.remove();
}
// Adapt 'hasMore'
it = codegenSecurities.iterator();
while (it.hasNext()) {
final CodegenSecurity security = it.next();
security.hasMore = it.hasNext();
}
if (codegenSecurities.isEmpty())
return null;
return codegenSecurities;
}
@Override
public String toOperationId(String operationId) {
return super.toOperationId(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, operationId));
}
private String formatIdentifier(String name, boolean capitalized) {
String identifier = camelize(name, true);
if (capitalized)
identifier = StringUtils.capitalize(identifier);
if (identifier.matches("[a-zA-Z_$][\\w_$]+") && !reservedWords.contains(identifier))
return identifier;
return escapeReservedWord(identifier);
}
@Override
public String toParamName(String name) { return formatIdentifier(name, false); }
@Override
public String toVarName(String name) {
return formatIdentifier(name, false);
}
@Override
public String toEnumName(CodegenProperty property)
{
return formatIdentifier(property.baseName, true);
}
@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type;
if (typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if (languageSpecificPrimitives.contains(type))
return toModelName(type);
} else
type = swaggerType;
return toModelName(type);
}
@Override
public String toInstantiationType(Property p) {
if (p instanceof MapProperty) {
MapProperty ap = (MapProperty) p;
String inner = getSwaggerType(ap.getAdditionalProperties());
return instantiationTypes.get("map") + "[String, " + inner + "]";
} else if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
String inner = getSwaggerType(ap.getItems());
return instantiationTypes.get("array") + "[" + inner + "]";
} else
return null;
}
public String toDefaultValue(Property p) {
if (!p.getRequired())
return "None";
if (p instanceof StringProperty)
return "null";
else if (p instanceof BooleanProperty)
return "null";
else if (p instanceof DateProperty)
return "null";
else if (p instanceof DateTimeProperty)
return "null";
else if (p instanceof DoubleProperty)
return "null";
else if (p instanceof FloatProperty)
return "null";
else if (p instanceof IntegerProperty)
return "null";
else if (p instanceof LongProperty)
return "null";
else if (p instanceof MapProperty) {
MapProperty ap = (MapProperty) p;
String inner = getSwaggerType(ap.getAdditionalProperties());
return "Map[String, " + inner + "].empty ";
} else if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
String inner = getSwaggerType(ap.getItems());
return "Seq[" + inner + "].empty ";
} else
return "null";
}
private static abstract class CustomLambda implements Mustache.Lambda {
@Override
public void execute(Template.Fragment frag, Writer out) throws IOException {
final StringWriter tempWriter = new StringWriter();
frag.execute(tempWriter);
out.write(formatFragment(tempWriter.toString()));
}
public abstract String formatFragment(String fragment);
}
private static class JavadocLambda extends CustomLambda {
@Override
public String formatFragment(String fragment) {
final String[] lines = fragment.split("\\r?\\n");
final StringBuilder sb = new StringBuilder();
sb.append(" /**\n");
for (String line : lines) {
sb.append(" * ").append(line).append("\n");
}
sb.append(" */\n");
return sb.toString();
}
}
private static class CapitalizeLambda extends CustomLambda {
@Override
public String formatFragment(String fragment) {
return StringUtils.capitalize(fragment);
}
}
private static class CamelizeLambda extends CustomLambda {
private final boolean capitalizeFirst;
public CamelizeLambda(boolean capitalizeFirst) {
this.capitalizeFirst = capitalizeFirst;
}
@Override
public String formatFragment(String fragment) {
return camelize(fragment, !capitalizeFirst);
}
}
private class EnumEntryLambda extends CustomLambda {
@Override
public String formatFragment(String fragment) {
return formatIdentifier(fragment, true);
}
}
}