From adb26d83f7a0d515f3c0c1a9fe63840b5727a12a Mon Sep 17 00:00:00 2001 From: Johannes Fiala Date: Sat, 5 Dec 2015 17:35:18 +0100 Subject: [PATCH] Add basic JS SDK support, see Document client SDK #1294 --- .../languages/JavascriptClientCodegen.java | 599 ++++++++++++++++ .../resources/Javascript/ApiClient.mustache | 654 ++++++++++++++++++ .../Javascript/Configuration.mustache | 22 + .../main/resources/Javascript/JSON.mustache | 55 ++ .../main/resources/Javascript/Pair.mustache | 39 ++ .../resources/Javascript/StringUtil.mustache | 51 ++ .../resources/Javascript/TypeRef.mustache | 26 + .../main/resources/Javascript/api.mustache | 113 +++ .../Javascript/apiException.mustache | 69 ++ .../Javascript/build.gradle.mustache | 107 +++ .../resources/Javascript/enumClass.mustache | 7 + .../Javascript/generatedAnnotation.mustache | 1 + .../Javascript/gradle.properties.mustache | 2 + .../main/resources/Javascript/model.mustache | 41 ++ .../resources/Javascript/model_full.mustache | 61 ++ .../main/resources/Javascript/pom.mustache | 171 +++++ .../Javascript/settings.gradle.mustache | 1 + 17 files changed, 2019 insertions(+) create mode 100644 modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/Configuration.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/JSON.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/Pair.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/StringUtil.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/TypeRef.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/api.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/apiException.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/build.gradle.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/enumClass.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/gradle.properties.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/model.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/model_full.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/pom.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/settings.gradle.mustache diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java new file mode 100644 index 00000000000..0beda074ea9 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java @@ -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 = "io.swagger.client.api"; + modelPackage = "io.swagger.client.model"; + + reservedWords = new HashSet( + 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( + 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("", "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) + ""; + } + 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()"; + } else { + pattern = "new HashMap()"; + } + 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 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 postProcessModels(Map objs) { + List models = (List) objs.get("models"); + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + for (CodegenProperty var : cm.vars) { + Map allowableValues = var.allowableValues; + + // handle ArrayProperty + if (var.items != null) { + allowableValues = var.items.allowableValues; + } + + if (allowableValues == null) { + continue; + } + List values = (List) allowableValues.get("values"); + if (values == null) { + continue; + } + + // put "enumVars" map into `allowableValues", including `name` and `value` + List> enumVars = new ArrayList>(); + String commonPrefix = findCommonPrefixOfVars(values); + int truncateIdx = commonPrefix.length(); + for (String value : values) { + Map enumVar = new HashMap(); + 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 postProcessOperations(Map objs) { + if("retrofit".equals(getLibrary())) { + Map operations = (Map) objs.get("operations"); + if (operations != null) { + List ops = (List) operations.get("operation"); + for (CodegenOperation operation : ops) { + if (operation.hasConsumes == Boolean.TRUE) { + Map 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 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 parentModelCodegenProperties = parentCodegenModel.vars; + List 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 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; + } + +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache new file mode 100644 index 00000000000..18d27ede7c3 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache @@ -0,0 +1,654 @@ +package {{invokerPackage}}; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.api.client.filter.LoggingFilter; +import com.sun.jersey.api.client.WebResource.Builder; + +import com.sun.jersey.multipart.FormDataMultiPart; +import com.sun.jersey.multipart.file.FileDataBodyPart; + +import javax.ws.rs.core.Response.Status.Family; +import javax.ws.rs.core.MediaType; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Map.Entry; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Date; +import java.util.TimeZone; + +import java.net.URLEncoder; + +import java.io.IOException; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.io.DataInputStream; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.text.ParseException; + +import {{invokerPackage}}.auth.Authentication; +import {{invokerPackage}}.auth.HttpBasicAuth; +import {{invokerPackage}}.auth.ApiKeyAuth; +import {{invokerPackage}}.auth.OAuth; + +{{>generatedAnnotation}} +public class ApiClient { + private Map hostMap = new HashMap(); + private Map defaultHeaderMap = new HashMap(); + private boolean debugging = false; + private String basePath = "{{basePath}}"; + private JSON json = new JSON(); + + private Map authentications; + + private int statusCode; + private Map> responseHeaders; + + private DateFormat dateFormat; + + public ApiClient() { + // Use ISO 8601 format for date and datetime. + // See https://en.wikipedia.org/wiki/ISO_8601 + this.dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + // Use UTC as the default time zone. + this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + // Set default User-Agent. + setUserAgent("Java-Swagger"); + + // Setup authentications (key: authentication name, value: authentication). + authentications = new HashMap();{{#authMethods}}{{#isBasic}} + authentications.put("{{name}}", new HttpBasicAuth());{{/isBasic}}{{#isApiKey}} + authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}} + authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}} + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + public String getBasePath() { + return basePath; + } + + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + /** + * Gets the status code of the previous request + */ + public int getStatusCode() { + return statusCode; + } + + /** + * Gets the response headers of the previous request + */ + public Map> getResponseHeaders() { + return responseHeaders; + } + + /** + * Get authentications (key: authentication name, value: authentication). + */ + public Map getAuthentications() { + return authentications; + } + + /** + * Get authentication for the given name. + * + * @param authName The authentication name + * @return The authentication, null if not found + */ + public Authentication getAuthentication(String authName) { + return authentications.get(authName); + } + + /** + * Helper method to set username for the first HTTP basic authentication. + */ + public void setUsername(String username) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setUsername(username); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set password for the first HTTP basic authentication. + */ + public void setPassword(String password) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setPassword(password); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set API key value for the first API key authentication. + */ + public void setApiKey(String apiKey) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKey(apiKey); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set API key prefix for the first API key authentication. + */ + public void setApiKeyPrefix(String apiKeyPrefix) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Set the User-Agent header's value (by adding to the default header map). + */ + public ApiClient setUserAgent(String userAgent) { + addDefaultHeader("User-Agent", userAgent); + return this; + } + + /** + * Add a default header. + * + * @param key The header's key + * @param value The header's value + */ + public ApiClient addDefaultHeader(String key, String value) { + defaultHeaderMap.put(key, value); + return this; + } + + /** + * Check that whether debugging is enabled for this API client. + */ + public boolean isDebugging() { + return debugging; + } + + /** + * Enable/disable debugging for this API client. + * + * @param debugging To enable (true) or disable (false) debugging + */ + public ApiClient setDebugging(boolean debugging) { + this.debugging = debugging; + return this; + } + + /** + * Get the date format used to parse/format date parameters. + */ + public DateFormat getDateFormat() { + return dateFormat; + } + + /** + * Set the date format used to parse/format date parameters. + */ + public ApiClient setDateFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + return this; + } + + /** + * Parse the given string into Date object. + */ + public Date parseDate(String str) { + try { + return dateFormat.parse(str); + } catch (java.text.ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * Format the given Date object into string. + */ + public String formatDate(Date date) { + return dateFormat.format(date); + } + + /** + * Format the given parameter object into string. + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date) { + return formatDate((Date) param); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for(Object o : (Collection)param) { + if(b.length() > 0) { + b.append(","); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /* + Format to {@code Pair} objects. + */ + public List parameterToPairs(String collectionFormat, String name, Object value){ + List params = new ArrayList(); + + // preconditions + if (name == null || name.isEmpty() || value == null) return params; + + Collection valueCollection = null; + if (value instanceof Collection) { + valueCollection = (Collection) value; + } else { + params.add(new Pair(name, parameterToString(value))); + return params; + } + + if (valueCollection.isEmpty()){ + return params; + } + + // get the collection format + collectionFormat = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat); // default: csv + + // create the params based on the collection format + if (collectionFormat.equals("multi")) { + for (Object item : valueCollection) { + params.add(new Pair(name, parameterToString(item))); + } + + return params; + } + + String delimiter = ","; + + if (collectionFormat.equals("csv")) { + delimiter = ","; + } else if (collectionFormat.equals("ssv")) { + delimiter = " "; + } else if (collectionFormat.equals("tsv")) { + delimiter = "\t"; + } else if (collectionFormat.equals("pipes")) { + delimiter = "|"; + } + + StringBuilder sb = new StringBuilder() ; + for (Object item : valueCollection) { + sb.append(delimiter); + sb.append(parameterToString(item)); + } + + params.add(new Pair(name, sb.substring(1))); + + return params; + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) return null; + if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0) return "application/json"; + if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + return contentTypes[0]; + } + + /** + * Escape the given string to be used as URL query value. + */ + public String escapeString(String str) { + try { + return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); + } catch (UnsupportedEncodingException e) { + return str; + } + } + + /** + * Serialize the given Java object into string according the given + * Content-Type (only JSON is supported for now). + */ + public String serialize(Object obj, String contentType) throws ApiException { + if (contentType.startsWith("application/json")) { + return json.serialize(obj); + } else { + throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); + } + } + + /** + * Deserialize response body to Java object according to the Content-Type. + */ + public T deserialize(ClientResponse response, TypeRef returnType) throws ApiException { + String contentType = null; + List contentTypes = response.getHeaders().get("Content-Type"); + if (contentTypes != null && !contentTypes.isEmpty()) + contentType = contentTypes.get(0); + if (contentType == null) + throw new ApiException(500, "missing Content-Type in response"); + + String body; + if (response.hasEntity()) + body = (String) response.getEntity(String.class); + else + body = ""; + + if (contentType.startsWith("application/json")) { + return json.deserialize(body, returnType); + } else if (returnType.getType().equals(String.class)) { + // Expecting string, return the raw response body. + return (T) body; + } else { + throw new ApiException( + 500, + "Content type \"" + contentType + "\" is not supported for type: " + + returnType.getType() + ); + } + } + + private ClientResponse getAPIResponse(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[] authNames) throws ApiException { + + if (body != null && binaryBody != null){ + throw new ApiException(500, "either body or binaryBody must be null"); + } + + updateParamsForAuth(authNames, queryParams, headerParams); + + Client client = getClient(); + + StringBuilder b = new StringBuilder(); + b.append("?"); + if (queryParams != null){ + for (Pair queryParam : queryParams){ + if (!queryParam.getName().isEmpty()) { + b.append(escapeString(queryParam.getName())); + b.append("="); + b.append(escapeString(queryParam.getValue())); + b.append("&"); + } + } + } + + String querystring = b.substring(0, b.length() - 1); + + Builder builder; + if (accept == null) + builder = client.resource(basePath + path + querystring).getRequestBuilder(); + else + builder = client.resource(basePath + path + querystring).accept(accept); + + for (String key : headerParams.keySet()) { + builder = builder.header(key, headerParams.get(key)); + } + for (String key : defaultHeaderMap.keySet()) { + if (!headerParams.containsKey(key)) { + builder = builder.header(key, defaultHeaderMap.get(key)); + } + } + + String encodedFormParams = null; + if (contentType.startsWith("multipart/form-data")) { + FormDataMultiPart mp = new FormDataMultiPart(); + for (Entry param: formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + mp.field(param.getKey(), file.getName()); + mp.bodyPart(new FileDataBodyPart(param.getKey(), file, MediaType.MULTIPART_FORM_DATA_TYPE)); + } else { + mp.field(param.getKey(), parameterToString(param.getValue()), MediaType.MULTIPART_FORM_DATA_TYPE); + } + } + body = mp; + } else if (contentType.startsWith("application/x-www-form-urlencoded")) { + encodedFormParams = this.getXWWWFormUrlencodedParams(formParams); + } + + ClientResponse response = null; + + if ("GET".equals(method)) { + response = (ClientResponse) builder.get(ClientResponse.class); + } else if ("POST".equals(method)) { + if (encodedFormParams != null) { + response = builder.type(contentType).post(ClientResponse.class, encodedFormParams); + } else if (body == null) { + if(binaryBody == null) + response = builder.post(ClientResponse.class, null); + else + response = builder.type(contentType).post(ClientResponse.class, binaryBody); + } else if (body instanceof FormDataMultiPart) { + response = builder.type(contentType).post(ClientResponse.class, body); + } else { + response = builder.type(contentType).post(ClientResponse.class, serialize(body, contentType)); + } + } else if ("PUT".equals(method)) { + if (encodedFormParams != null) { + response = builder.type(contentType).put(ClientResponse.class, encodedFormParams); + } else if(body == null) { + if(binaryBody == null) + response = builder.put(ClientResponse.class, null); + else + response = builder.type(contentType).put(ClientResponse.class, binaryBody); + } else { + response = builder.type(contentType).put(ClientResponse.class, serialize(body, contentType)); + } + } else if ("DELETE".equals(method)) { + if (encodedFormParams != null) { + response = builder.type(contentType).delete(ClientResponse.class, encodedFormParams); + } else if(body == null) { + if(binaryBody == null) + response = builder.delete(ClientResponse.class); + else + response = builder.type(contentType).delete(ClientResponse.class, binaryBody); + } else { + response = builder.type(contentType).delete(ClientResponse.class, serialize(body, contentType)); + } + } else { + throw new ApiException(500, "unknown method type " + method); + } + return response; + } + + /** + * Invoke API by sending HTTP request with the given options. + * + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "POST", "PUT", and "DELETE" + * @param queryParams The query parameters + * @param body The request body object - if it is not binary, otherwise null + * @param binaryBody The request body object - if it is binary, otherwise null + * @param headerParams The header parameters + * @param formParams The form parameters + * @param accept The request's Accept header + * @param contentType The request's Content-Type header + * @param authNames The authentications to apply + * @return The response body in type of string + */ + public T invokeAPI(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, TypeRef returnType) throws ApiException { + + ClientResponse response = getAPIResponse(path, method, queryParams, body, binaryBody, headerParams, formParams, accept, contentType, authNames); + + statusCode = response.getStatusInfo().getStatusCode(); + responseHeaders = response.getHeaders(); + + if(response.getStatusInfo() == ClientResponse.Status.NO_CONTENT) { + return null; + } else if (response.getStatusInfo().getFamily() == Family.SUCCESSFUL) { + if (returnType == null) + return null; + else + return deserialize(response, returnType); + } else { + String message = "error"; + String respBody = null; + if (response.hasEntity()) { + try { + respBody = String.valueOf(response.getEntity(String.class)); + message = respBody; + } catch (RuntimeException e) { + // e.printStackTrace(); + } + } + throw new ApiException( + response.getStatusInfo().getStatusCode(), + message, + response.getHeaders(), + respBody); + } + } + /** + * Invoke API by sending HTTP request with the given options - return binary result + * + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "POST", "PUT", and "DELETE" + * @param queryParams The query parameters + * @param body The request body object - if it is not binary, otherwise null + * @param binaryBody The request body object - if it is binary, otherwise null + * @param headerParams The header parameters + * @param formParams The form parameters + * @param accept The request's Accept header + * @param contentType The request's Content-Type header + * @param authNames The authentications to apply + * @return The response body in type of string + */ + public byte[] invokeBinaryAPI(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[]authNames) throws ApiException { + + ClientResponse response = getAPIResponse(path, method, queryParams, body, binaryBody, headerParams, formParams, accept, contentType, authNames); + + if(response.getStatusInfo() == ClientResponse.Status.NO_CONTENT) { + return null; + } + else if(response.getStatusInfo().getFamily() == Family.SUCCESSFUL) { + if(response.hasEntity()) { + DataInputStream stream = new DataInputStream(response.getEntityInputStream()); + byte[] data = new byte[response.getLength()]; + try { + stream.readFully(data); + } catch (IOException ex) { + throw new ApiException(500, "Error obtaining binary response data"); + } + return data; + } + else { + return new byte[0]; + } + } + else { + String message = "error"; + if(response.hasEntity()) { + try{ + message = String.valueOf(response.getEntity(String.class)); + } + catch (RuntimeException e) { + // e.printStackTrace(); + } + } + throw new ApiException( + response.getStatusInfo().getStatusCode(), + message); + } + } + + /** + * Update query and header parameters based on authentication settings. + * + * @param authNames The authentications to apply + */ + private void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams) { + for (String authName : authNames) { + Authentication auth = authentications.get(authName); + if (auth == null) throw new RuntimeException("Authentication undefined: " + authName); + auth.applyToParams(queryParams, headerParams); + } + } + + /** + * Encode the given form parameters as request body. + */ + private String getXWWWFormUrlencodedParams(Map formParams) { + StringBuilder formParamBuilder = new StringBuilder(); + + for (Entry param : formParams.entrySet()) { + String keyStr = param.getKey(); + String valueStr = parameterToString(param.getValue()); + try { + formParamBuilder.append(URLEncoder.encode(param.getKey(), "utf8")) + .append("=") + .append(URLEncoder.encode(valueStr, "utf8")); + formParamBuilder.append("&"); + } catch (UnsupportedEncodingException e) { + // move on to next + } + } + + String encodedFormParams = formParamBuilder.toString(); + if (encodedFormParams.endsWith("&")) { + encodedFormParams = encodedFormParams.substring(0, encodedFormParams.length() - 1); + } + + return encodedFormParams; + } + + /** + * Get an existing client or create a new client to handle HTTP request. + */ + private Client getClient() { + if(!hostMap.containsKey(basePath)) { + Client client = Client.create(); + if (debugging) + client.addFilter(new LoggingFilter()); + hostMap.put(basePath, client); + } + return hostMap.get(basePath); + } +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/Configuration.mustache b/modules/swagger-codegen/src/main/resources/Javascript/Configuration.mustache new file mode 100644 index 00000000000..4629c4e17be --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/Configuration.mustache @@ -0,0 +1,22 @@ +package {{invokerPackage}}; + +{{>generatedAnnotation}} +public class Configuration { + private static ApiClient defaultApiClient = new ApiClient(); + + /** + * Get the default API client, which would be used when creating API + * instances without providing an API client. + */ + public static ApiClient getDefaultApiClient() { + return defaultApiClient; + } + + /** + * Set the default API client, which would be used when creating API + * instances without providing an API client. + */ + public static void setDefaultApiClient(ApiClient apiClient) { + defaultApiClient = apiClient; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/JSON.mustache b/modules/swagger-codegen/src/main/resources/Javascript/JSON.mustache new file mode 100644 index 00000000000..43b38f6e21d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/JSON.mustache @@ -0,0 +1,55 @@ +package {{invokerPackage}}; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.joda.*; + +import java.io.IOException; + +{{>generatedAnnotation}} +public class JSON { + private ObjectMapper mapper; + + public JSON() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + mapper.registerModule(new JodaModule()); + } + + /** + * Serialize the given Java object into JSON string. + */ + public String serialize(Object obj) throws ApiException { + try { + if (obj != null) + return mapper.writeValueAsString(obj); + else + return null; + } catch (Exception e) { + throw new ApiException(400, e.getMessage()); + } + } + + /** + * Deserialize the given JSON string to Java object. + * + * @param body The JSON string + * @param returnType The type to deserialize inot + * @return The deserialized Java object + */ + public T deserialize(String body, TypeRef returnType) throws ApiException { + JavaType javaType = mapper.constructType(returnType.getType()); + try { + return mapper.readValue(body, javaType); + } catch (IOException e) { + if (returnType.getType().equals(String.class)) + return (T) body; + else + throw new ApiException(500, e.getMessage(), null, body); + } + } +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/Pair.mustache b/modules/swagger-codegen/src/main/resources/Javascript/Pair.mustache new file mode 100644 index 00000000000..e2a47317afe --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/Pair.mustache @@ -0,0 +1,39 @@ +package {{invokerPackage}}; + +{{>generatedAnnotation}} +public class Pair { + private String name = ""; + private String value = ""; + + public Pair (String name, String value) { + setName(name); + setValue(value); + } + + private void setName(String name) { + if (!isValidString(name)) return; + + this.name = name; + } + + private void setValue(String value) { + if (!isValidString(value)) return; + + this.value = value; + } + + public String getName() { + return this.name; + } + + public String getValue() { + return this.value; + } + + private boolean isValidString(String arg) { + if (arg == null) return false; + if (arg.trim().isEmpty()) return false; + + return true; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/StringUtil.mustache b/modules/swagger-codegen/src/main/resources/Javascript/StringUtil.mustache new file mode 100644 index 00000000000..c9583f1bc63 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/StringUtil.mustache @@ -0,0 +1,51 @@ +package {{invokerPackage}}; + +{{>generatedAnnotation}} +public class StringUtil { + /** + * Check if the given array contains the given value (with case-insensitive comparison). + * + * @param array The array + * @param value The value to search + * @return true if the array contains the value + */ + public static boolean containsIgnoreCase(String[] array, String value) { + for (String str : array) { + if (value == null && str == null) return true; + if (value != null && value.equalsIgnoreCase(str)) return true; + } + return false; + } + + /** + * Join an array of strings with the given separator. + *

+ * Note: This might be replaced by utility method from commons-lang or guava someday + * if one of those libraries is added as dependency. + *

+ * + * @param array The array of strings + * @param separator The separator + * @return the resulting string + */ + public static String join(String[] array, String separator) { + int len = array.length; + if (len == 0) return ""; + + StringBuilder out = new StringBuilder(); + out.append(array[0]); + for (int i = 1; i < len; i++) { + out.append(separator).append(array[i]); + } + return out.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + public static String toIndentedString(Object o) { + if (o == null) return "null"; + return o.toString().replace("\n", "\n "); + } +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/TypeRef.mustache b/modules/swagger-codegen/src/main/resources/Javascript/TypeRef.mustache new file mode 100644 index 00000000000..9e9ba5f8895 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/TypeRef.mustache @@ -0,0 +1,26 @@ +package {{invokerPackage}}; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +{{>generatedAnnotation}} +public class TypeRef { + private final Type type; + + public TypeRef() { + this.type = getGenericType(getClass()); + } + + private static Type getGenericType(Class klass) { + Type superclass = klass.getGenericSuperclass(); + if (superclass instanceof Class) { + throw new RuntimeException("No type parameter provided"); + } + ParameterizedType parameterized = (ParameterizedType) superclass; + return parameterized.getActualTypeArguments()[0]; + } + + public Type getType() { + return type; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache new file mode 100644 index 00000000000..9e41b237c68 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -0,0 +1,113 @@ +/* + * {{>generatedAnnotation}} + */ +function {{classname}}() { + var self = this; +{{#operations}} + {{#operation}} + /** + * {{summary}} + * {{notes}} +{{#allParams}} * @param {{=<% %>=}}{<% dataType %>} <%={{ }}=%> {{paramName}} {{description}} +{{/allParams}} * @param {function} callback the callback function + * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} + */ + self.{{nickname}} = function({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}, callback) { + + var {{localVariablePrefix}}postBody = {{#bodyParam}}{{^isBinary}}JSON.stringify({{paramName}}){{/isBinary}}{{#isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + var {{localVariablePrefix}}postBinaryBody = {{#bodyParam}}{{#isBinary}}{{paramName}}{{/isBinary}}{{^isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + {{#allParams}}{{#required}} + // verify the required parameter '{{paramName}}' is set + if ({{paramName}} == null) { + //throw new ApiException(400, "Missing the required parameter '{{paramName}}' when calling {{nickname}}"); + var errorRequiredMsg = "Missing the required parameter '{{paramName}}' when calling {{nickname}}"; + throw errorRequiredMsg; + } + {{/required}}{{/allParams}} + // create path and map variables + var {{localVariablePrefix}}path = '{{basePath}}' + self.replaceAll(self.replaceAll("{{{path}}}", "\\{format\\}","json"){{#pathParams}} +, "\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}apiClient.escapeString({{{paramName}}}.toString())){{/pathParams}}); + + var queryParams = {}; + var headerParams = {}; + var formParams = {}; + + {{#queryParams}} + queryParams.{{baseName}} = {{paramName}}; + {{/queryParams}} + {{#headerParams}}if ({{paramName}} != null) + {{localVariablePrefix}}headerParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}})); + {{/headerParams}} + {{#formParams}}if ({{paramName}} != null) + {{localVariablePrefix}}formParams.put("{{baseName}}", {{paramName}}); + {{/formParams}} + + path += self.createQueryString(queryParams); + + if (console) { + console.log('path: ' + path); + console.log('queryParams: ' + queryParams); + } + + {{#isResponseBinary}} + byte[] {{localVariablePrefix}}response = null; + {{localVariablePrefix}}response = {{localVariablePrefix}}apiClient.invokeBinaryAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams,{{localVariablePrefix}} postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames); + return {{localVariablePrefix}}response; + {{/isResponseBinary}} + + {{^isResponseBinary}} + {{#returnType}} + //TypeRef {{localVariablePrefix}}returnType = new TypeRef<{{{returnType}}}>() {}; + //return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); + + var options = {type: "{{httpMethod}}", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); + + + request.done(function(response, textStatus, jqXHR){ + /** + * @returns {{{returnType}}} + */ + var myResponse = response; + callback(myResponse, textStatus, jqXHR); + }); + + {{/returnType}}{{^returnType}} + {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, null); + {{/returnType}} + {{/isResponseBinary}} + + + } + {{/operation}} + +{{/operations}} + +self.replaceAll = function (haystack, needle, replace) { + var result= haystack; + if (needle !=null && replace!=null) { + result= haystack.replace(new RegExp(needle, 'g'), replace); + } + return result; +} + +self.createQueryString = function (queryParams) { + var queryString =''; + var i = 0; + for (var queryParamName in queryParams) { + if (i==0) { + queryString += '?' ; + } else { + queryString += '&' ; + } + + queryString += queryParamName + '=' + encodeURIComponent(queryParams[queryParamName]); + i++; + } + + return queryString; +} +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/apiException.mustache b/modules/swagger-codegen/src/main/resources/Javascript/apiException.mustache new file mode 100644 index 00000000000..b9a62a6b231 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/apiException.mustache @@ -0,0 +1,69 @@ +package {{invokerPackage}}; + +import java.util.Map; +import java.util.List; + +{{>generatedAnnotation}} +public class ApiException extends Exception { + private int code = 0; + private Map> responseHeaders = null; + private String responseBody = null; + + public ApiException() {} + + public ApiException(Throwable throwable) { + super(throwable); + } + + public ApiException(String message) { + super(message); + } + + public ApiException(String message, Throwable throwable, int code, Map> responseHeaders, String responseBody) { + super(message, throwable); + this.code = code; + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + public ApiException(String message, int code, Map> responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } + + public ApiException(String message, Throwable throwable, int code, Map> responseHeaders) { + this(message, throwable, code, responseHeaders, null); + } + + public ApiException(int code, Map> responseHeaders, String responseBody) { + this((String) null, (Throwable) null, code, responseHeaders, responseBody); + } + + public ApiException(int code, String message) { + super(message); + this.code = code; + } + + public ApiException(int code, String message, Map> responseHeaders, String responseBody) { + this(code, message); + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + public int getCode() { + return code; + } + + /** + * Get the HTTP response headers. + */ + public Map> getResponseHeaders() { + return responseHeaders; + } + + /** + * Get the HTTP response body. + */ + public String getResponseBody() { + return responseBody; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/build.gradle.mustache b/modules/swagger-codegen/src/main/resources/Javascript/build.gradle.mustache new file mode 100644 index 00000000000..971dcd816a4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/build.gradle.mustache @@ -0,0 +1,107 @@ +group = '{{groupId}}' +version = '{{artifactVersion}}' + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.github.dcendents:android-maven-plugin:1.2' + } +} + +repositories { + jcenter() +} + + +if(hasProperty('target') && target == 'android') { + + apply plugin: 'com.android.library' + apply plugin: 'com.github.dcendents.android-maven' + + android { + compileSdkVersion 22 + buildToolsVersion '22.0.0' + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + // Rename the aar correctly + libraryVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.aar')) { + def fileName = "${project.name}-${variant.baseName}-${version}.aar" + output.outputFile = new File(outputFile.parent, fileName) + } + } + } + } + + afterEvaluate { + android.libraryVariants.all { variant -> + def task = project.tasks.create "jar${variant.name.capitalize()}", Jar + task.description = "Create jar artifact for ${variant.name}" + task.dependsOn variant.javaCompile + task.from variant.javaCompile.destinationDir + task.destinationDir = project.file("${project.buildDir}/outputs/jar") + task.archiveName = "${project.name}-${variant.baseName}-${version}.jar" + artifacts.add('archives', task); + } + } + + task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' + } + + artifacts { + archives sourcesJar + } + +} else { + + apply plugin: 'java' + apply plugin: 'maven' + + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + + install { + repositories.mavenInstaller { + pom.artifactId = '{{artifactId}}' + } + } + + task execute(type:JavaExec) { + main = System.getProperty('mainClass') + classpath = sourceSets.main.runtimeClasspath + } +} + +ext { + swagger_annotations_version = "1.5.0" + jackson_version = "2.4.2" + jersey_version = "1.18" + jodatime_version = "2.3" + junit_version = "4.8.1" +} + +dependencies { + compile "io.swagger:swagger-annotations:$swagger_annotations_version" + compile "com.sun.jersey:jersey-client:$jersey_version" + compile "com.sun.jersey.contribs:jersey-multipart:$jersey_version" + compile "com.fasterxml.jackson.core:jackson-core:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:2.1.5" + compile "joda-time:joda-time:$jodatime_version" + testCompile "junit:junit:$junit_version" +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/enumClass.mustache b/modules/swagger-codegen/src/main/resources/Javascript/enumClass.mustache new file mode 100644 index 00000000000..bbbd802800d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/enumClass.mustache @@ -0,0 +1,7 @@ +function {{datatypeWithEnum}}() { + var self = this; + +{{#allowableValues}}{{#enumVars}} self.{{name}} = "{{value}}"{{^-last}}, + {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}} + +} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache b/modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache new file mode 100644 index 00000000000..49110fc1ad9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache @@ -0,0 +1 @@ +@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}") \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Javascript/gradle.properties.mustache b/modules/swagger-codegen/src/main/resources/Javascript/gradle.properties.mustache new file mode 100644 index 00000000000..05644f0754a --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/gradle.properties.mustache @@ -0,0 +1,2 @@ +# Uncomment to build for Android +#target = android \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Javascript/model.mustache b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache new file mode 100644 index 00000000000..8e3c02ffd04 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache @@ -0,0 +1,41 @@ +{{#models}}{{#model}} +{{#vars}}{{#isEnum}}{{>enumClass}}{{/isEnum}}{{#items.isEnum}}{{#items}} +{{>enumClass}}{{/items}}*/{{/items.isEnum}}{{/vars}} +{{#description}}/** + * {{description}} + **/{{/description}} +function {{classname}}() { {{#parent}}/* extends {{{parent}}}*/{{/parent}} + var self = this; + {{#vars}} + /**{{#description}} + * {{{description}}}{{/description}} + * datatype: {{{datatypeWithEnum}}}{{#minimum}} + * minimum: {{minimum}}{{/minimum}}{{#maximum}} + * maximum: {{maximum}}{{/maximum}} + **/ + self.{{name}} = {{{defaultValue}}}; + {{/vars}} + + {{#vars}} + /**{{#description}} + * get {{{description}}}{{/description}}{{#minimum}} + * minimum: {{minimum}}{{/minimum}}{{#maximum}} + * maximum: {{maximum}}{{/maximum}} + * @return {{=<% %>=}}{<% datatypeWithEnum %>}<%={{ }}=%> + **/ + self.{{getter}} = function() { + return self.{{name}}; + } + + /**{{#description}} + * set {{{description}}}{{/description}} + * @param {{=<% %>=}}{<% datatypeWithEnum %>}<%={{ }}=%> {{name}} + **/ + self.{{setter}} = function ({{name}}) { + self.{{name}} = {{name}}; + } + {{/vars}} + +} +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/model_full.mustache b/modules/swagger-codegen/src/main/resources/Javascript/model_full.mustache new file mode 100644 index 00000000000..11f4b9c7fca --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/model_full.mustache @@ -0,0 +1,61 @@ +//package {{package}}; + +//import {{invokerPackage}}.StringUtil; +//{{#imports}}import {{import}}; +//{{/imports}} + +//{{#serializableModel}} +//import java.io.Serializable;{{/serializableModel}} + +//import io.swagger.annotations.*; +//import com.fasterxml.jackson.annotation.JsonProperty; +{{#models}} + +{{#model}}{{#description}} +/** + * {{description}} + **/{{/description}} +//@ApiModel(description = "{{{description}}}") +// {{>generatedAnnotation}} +//public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} /* {{#serializableModel}}implements Serializable{{/serializableModel}} */ { +function {{classname}}() { + var self = this; + + {{#vars}}/*{{#isEnum}} + +{{>enumClass}}{{/isEnum}}{{#items.isEnum}}{{#items}} + +{{>enumClass}}{{/items}}{{/items.isEnum}}*/ + //private {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}}; + self.{{name}} = {{{defaultValue}}}; + {{/vars}} + + {{#vars}} + /**{{#description}} + * {{{description}}}{{/description}}{{#minimum}} + * minimum: {{minimum}}{{/minimum}}{{#maximum}} + * maximum: {{maximum}}{{/maximum}} + **/ + //@ApiModelProperty({{#required}}required = {{required}}, {{/required}}value = "{{{description}}}") + //@JsonProperty("{{baseName}}") + //public {{{datatypeWithEnum}}} {{getter}}() { + // return {{name}}; + //} + //public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { + // this.{{name}} = {{name}}; + //} + + {{/vars}} + + //@Override + //public String toString() { + // StringBuilder sb = new StringBuilder(); + // sb.append("class {{classname}} {\n"); + // {{#parent}}sb.append(" ").append(StringUtil.toIndentedString(super.toString())).append("\n");{{/parent}} + // {{#vars}}sb.append(" {{name}}: ").append(StringUtil.toIndentedString({{name}})).append("\n"); + // {{/vars}}sb.append("}"); + // return sb.toString(); + //} +} +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/pom.mustache b/modules/swagger-codegen/src/main/resources/Javascript/pom.mustache new file mode 100644 index 00000000000..c7dd1865518 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/pom.mustache @@ -0,0 +1,171 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + scm:git:git@github.com:swagger-api/swagger-mustache.git + scm:git:git@github.com:swagger-api/swagger-codegen.git + https://github.com/swagger-api/swagger-codegen + + + 2.2.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + io.swagger + swagger-annotations + ${swagger-annotations-version} + + + + + com.sun.jersey + jersey-client + ${jersey-version} + + + com.sun.jersey.contribs + jersey-multipart + ${jersey-version} + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + 2.1.5 + + + joda-time + joda-time + ${jodatime-version} + + + + + junit + junit + ${junit-version} + test + + + + 1.5.4 + 1.18 + 2.4.2 + 2.3 + 1.0.0 + 4.8.1 + + diff --git a/modules/swagger-codegen/src/main/resources/Javascript/settings.gradle.mustache b/modules/swagger-codegen/src/main/resources/Javascript/settings.gradle.mustache new file mode 100644 index 00000000000..b8fd6c4c41f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/settings.gradle.mustache @@ -0,0 +1 @@ +rootProject.name = "{{artifactId}}" \ No newline at end of file