diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/AbstractGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/AbstractGenerator.java new file mode 100644 index 00000000000..3fc7dfb8da2 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/AbstractGenerator.java @@ -0,0 +1,60 @@ +package io.swagger.codegen; + +import com.samskivert.mustache.*; + +import java.util.regex.Pattern; +import java.io.*; + +public abstract class AbstractGenerator { + + public File writeToFile(String filename, String contents) throws IOException { + System.out.println("writing file " + filename); + File output = new File(filename); + + if(output.getParent() != null && !new File(output.getParent()).exists()) { + File parent = new File(output.getParent()); + parent.mkdirs(); + } + Writer out = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(output), "UTF-8")); + + out.write(contents); + out.close(); + return output; + } + + public String readTemplate(String name) { + try{ + Reader reader = getTemplateReader(name); + if(reader == null) + throw new RuntimeException("no file found"); + java.util.Scanner s = new java.util.Scanner(reader).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } + catch(Exception e) { + e.printStackTrace(); + } + throw new RuntimeException("can't load template " + name); + } + + public Reader getTemplateReader(String name) { + try{ + InputStream is = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(name)); + if(is == null) + is = new FileInputStream(new File(name)); + if(is == null) + throw new RuntimeException("no file found"); + return new InputStreamReader(is); + } + catch(Exception e) { + e.printStackTrace(); + } + throw new RuntimeException("can't load template " + name); + } + + private String getCPResourcePath(String name) { + if (!"/".equals(File.separator)) + return name.replaceAll(Pattern.quote(File.separator), "/"); + return name; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CliOption.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CliOption.java new file mode 100644 index 00000000000..3f4334507ae --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CliOption.java @@ -0,0 +1,23 @@ +package io.swagger.codegen; + +public class CliOption { + private final String opt; + private String description; + + public CliOption(String opt, String description) { + this.opt = opt; + this.description = description; + } + + public String getOpt() { + return opt; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/ClientOptInput.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/ClientOptInput.java new file mode 100644 index 00000000000..54056583463 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/ClientOptInput.java @@ -0,0 +1,104 @@ +/** + * Copyright 2015 Reverb, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.swagger.codegen; + +import io.swagger.codegen.ClientOpts; +import io.swagger.annotations.*; +import io.swagger.models.Swagger; +import io.swagger.models.auth.AuthorizationValue; + +import java.util.*; +import java.net.URLEncoder; +import java.net.URLDecoder; + +public class ClientOptInput { + private ClientOpts opts; + private Swagger swagger; + private List auths; + protected CodegenConfig config; + + public ClientOptInput swagger(Swagger swagger) { + this.setSwagger(swagger); + return this; + } + public ClientOptInput opts(ClientOpts opts) { + this.setOpts(opts); + return this; + } + + public void setAuth(String urlEncodedAuthString) { + List auths = new ArrayList(); + if(urlEncodedAuthString != null && !"".equals(urlEncodedAuthString)) { + String[] parts = urlEncodedAuthString.split(","); + for(String part : parts) { + String[] kvPair = part.split(":"); + if(kvPair.length == 2) { + auths.add(new AuthorizationValue(URLDecoder.decode(kvPair[0]), URLDecoder.decode(kvPair[1]), "header")); + } + } + } + this.auths = auths; + } + public String getAuth() { + if(auths != null) { + StringBuilder b = new StringBuilder(); + for(AuthorizationValue v : auths) { + try { + if(b.toString().length() > 0) + b.append(","); + b.append(URLEncoder.encode(v.getKeyName(), "UTF-8")) + .append(":") + .append(URLEncoder.encode(v.getValue(), "UTF-8")); + } + catch (Exception e) { + // continue + e.printStackTrace(); + } + } + return b.toString(); + } + else + return null; + } + public List getAuthorizationValues() { + return auths; + } + + public CodegenConfig getConfig() { + return config; + } + public void setConfig(CodegenConfig config) { + this.config = config; + } + + public void setOpts(ClientOpts opts) { + this.opts = opts; + } + + public ClientOpts getOpts() { + return opts; + } + + public void setSwagger(Swagger swagger) { + this.swagger = swagger; + } + + @ApiModelProperty(dataType="Object") + public Swagger getSwagger() { + return swagger; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/ClientOpts.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/ClientOpts.java new file mode 100644 index 00000000000..465fed820da --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/ClientOpts.java @@ -0,0 +1,52 @@ +package io.swagger.codegen; + +import io.swagger.codegen.auth.*; + +import java.util.*; + +public class ClientOpts { + protected String uri; + protected String target; + protected AuthMethod auth; + protected Map properties = new HashMap(); + protected String outputDirectory; + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public String getTarget() { + return target; + } + public void setTarget(String target) { + this.target = target; + } + + public Map getProperties() { + return properties; + } + public void setProperties(Map properties) { + this.properties = properties; + } + + public String getOutputDirectory() { + return outputDirectory; + } + public void setOutputDirectory(String outputDirectory) { + this.outputDirectory = outputDirectory; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ClientOpts: {\n"); + sb.append(" uri: ").append(uri).append(","); + sb.append(" auth: ").append(auth).append(","); + sb.append(properties); + sb.append("}"); + return sb.toString(); + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/Codegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/Codegen.java new file mode 100644 index 00000000000..8772a8b8ced --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/Codegen.java @@ -0,0 +1,143 @@ +package io.swagger.codegen; + +import io.swagger.codegen.languages.*; +import io.swagger.models.Swagger; +import io.swagger.models.auth.AuthorizationValue; +import io.swagger.util.*; + +import io.swagger.parser.SwaggerParser; + +import org.apache.commons.cli.*; + +import java.io.File; +import java.util.*; + +/** + * @deprecated use instead {@link io.swagger.codegen.DefaultGenerator} + * or cli interface from https://github.com/swagger-api/swagger-codegen/pull/547 + */ +@Deprecated +public class Codegen extends DefaultGenerator { + static Map configs = new HashMap(); + static String configString; + static { + List extensions = getExtensions(); + StringBuilder sb = new StringBuilder(); + + for(CodegenConfig config : extensions) { + if(sb.toString().length() != 0) + sb.append(", "); + sb.append(config.getName()); + configs.put(config.getName(), config); + configString = sb.toString(); + } + } + + static String debugInfoOptions = "\nThe following additional debug options are available for all codegen targets:" + + "\n -DdebugSwagger prints the swagger specification as interpreted by the codegen" + + "\n -DdebugModels prints models passed to the template engine" + + "\n -DdebugOperations prints operations passed to the template engine" + + "\n -DdebugSupportingFiles prints additional data passed to the template engine"; + public static void main(String[] args) { + + StringBuilder sb = new StringBuilder(); + + Options options = new Options(); + options.addOption("h", "help", false, "shows this message"); + options.addOption("l", "lang", true, "client language to generate.\nAvailable languages include:\n\t[" + configString + "]"); + options.addOption("o", "output", true, "where to write the generated files"); + options.addOption("i", "input-spec", true, "location of the swagger spec, as URL or file"); + options.addOption("t", "template-dir", true, "folder containing the template files"); + options.addOption("d", "debug-info", false, "prints additional info for debugging"); + options.addOption("a", "auth", true, "adds authorization headers when fetching the swagger definitions remotely. Pass in a URL-encoded string of name:header with a comma separating multiple values"); + + ClientOptInput clientOptInput = new ClientOptInput(); + ClientOpts clientOpts = new ClientOpts(); + Swagger swagger = null; + + CommandLine cmd = null; + try { + CommandLineParser parser = new BasicParser(); + CodegenConfig config = null; + + cmd = parser.parse(options, args); + if (cmd.hasOption("d")) { + usage(options); + System.out.println(debugInfoOptions); + return; + } + if (cmd.hasOption("a")) + clientOptInput.setAuth(cmd.getOptionValue("a")); + if (cmd.hasOption("l")) + clientOptInput.setConfig(getConfig(cmd.getOptionValue("l"))); + else { + usage(options); + return; + } + if (cmd.hasOption("o")) + clientOptInput.getConfig().setOutputDir(cmd.getOptionValue("o")); + if (cmd.hasOption("h")) { + if(cmd.hasOption("l")) { + config = getConfig(String.valueOf(cmd.getOptionValue("l"))); + if(config != null) { + options.addOption("h", "help", true, config.getHelp()); + usage(options); + return; + } + } + usage(options); + return; + } + if (cmd.hasOption("i")) + swagger = new SwaggerParser().read(cmd.getOptionValue("i"), clientOptInput.getAuthorizationValues(), true); + if (cmd.hasOption("t")) + clientOpts.getProperties().put("templateDir", String.valueOf(cmd.getOptionValue("t"))); + } + catch (Exception e) { + usage(options); + return; + } + try{ + clientOptInput + .opts(clientOpts) + .swagger(swagger); + new Codegen().opts(clientOptInput).generate(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public static List getExtensions() { + ServiceLoader loader = ServiceLoader.load(CodegenConfig.class); + List output = new ArrayList(); + Iterator itr = loader.iterator(); + while(itr.hasNext()) { + output.add(itr.next()); + } + return output; + } + + static void usage(Options options) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp( "Codegen", options ); + } + + public static CodegenConfig getConfig(String name) { + if(configs.containsKey(name)) { + return configs.get(name); + } + else { + // see if it's a class + try { + System.out.println("loading class " + name); + Class customClass = Class.forName(name); + System.out.println("loaded"); + return (CodegenConfig)customClass.newInstance(); + } + catch (Exception e) { + throw new RuntimeException("can't load class " + name); + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConfig.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConfig.java new file mode 100644 index 00000000000..4ff582dcb11 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConfig.java @@ -0,0 +1,64 @@ +package io.swagger.codegen; + +import io.swagger.models.*; +import io.swagger.models.auth.SecuritySchemeDefinition; +import io.swagger.models.properties.*; + +import java.util.*; + +public interface CodegenConfig { + CodegenType getTag(); + String getName(); + String getHelp(); + Map additionalProperties(); + String apiPackage(); + String apiFileFolder(); + String fileSuffix(); + String outputFolder(); + String templateDir(); + String modelFileFolder(); + String modelPackage(); + String toApiName(String name); + String toApiVarName(String name); + String toModelName(String name); + String toParamName(String name); + String escapeText(String text); + String escapeReservedWord(String name); + String getTypeDeclaration(Property p); + String getTypeDeclaration(String name); + void processOpts(); + List cliOptions(); + String generateExamplePath(String path, Operation operation); + + Set reservedWords(); + + List supportingFiles(); + + void setOutputDir(String dir); + String getOutputDir(); + + CodegenModel fromModel(String name, Model model); + CodegenOperation fromOperation(String resourcePath, String httpMethod, Operation operation, Map definitions); + List fromSecurity(Map schemes); + + Set defaultIncludes(); + Map typeMapping(); + Map instantiationTypes(); + Map importMapping(); + Map apiTemplateFiles(); + Map modelTemplateFiles(); + void processSwagger(Swagger swagger); + + String toApiFilename(String name); + String toModelFilename(String name); + String toModelImport(String name); + String toApiImport(String name); + void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations); + Map postProcessModels(Map objs); + Map postProcessOperations(Map objs); + Map postProcessSupportingFileData(Map objs); + + String apiFilename(String templateName, String tag); + + boolean shouldOverwrite(String filename); +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java new file mode 100644 index 00000000000..0cacc3a56e3 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java @@ -0,0 +1,16 @@ +package io.swagger.codegen; + +import io.swagger.models.*; +import io.swagger.models.properties.*; + +import java.util.*; + +public class CodegenModel { + public String parent; + public String name, classname, description, classVarName, modelJson; + public String defaultValue; + public List vars = new ArrayList(); + public Set imports = new HashSet(); + public Boolean hasVars, emptyVars, hasMoreModels, hasEnums; + public ExternalDocs externalDocs; +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModelFactory.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModelFactory.java new file mode 100644 index 00000000000..06dfcfbc86b --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModelFactory.java @@ -0,0 +1,38 @@ +package io.swagger.codegen; + +import java.util.HashMap; +import java.util.Map; + +public final class CodegenModelFactory { + + private static final Map> typeMapping = new HashMap>(); + + /** + * Configure a different implementation class. + * @param type the type that shall be replaced + * @param implementation the implementation class must extend the default class and must provide a public no-arg constructor + */ + public static void setTypeMapping(CodegenModelType type, Class implementation) { + if (!type.getDefaultImplementation().isAssignableFrom(implementation)) { + throw new IllegalArgumentException(implementation.getSimpleName() + " doesn't extend " + type.getDefaultImplementation().getSimpleName()); + } + try { + implementation.newInstance(); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + typeMapping.put(type, implementation); + } + + @SuppressWarnings("unchecked") + public static T newInstance(CodegenModelType type) { + Class classType = typeMapping.get(type); + try { + return (T) (classType != null ? classType : type.getDefaultImplementation()).newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModelType.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModelType.java new file mode 100644 index 00000000000..8c082a899cd --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModelType.java @@ -0,0 +1,21 @@ +package io.swagger.codegen; + +public enum CodegenModelType { + + MODEL(CodegenModel.class), + OPERATION(CodegenOperation.class), + PARAMETER(CodegenParameter.class), + PROPERTY(CodegenProperty.class), + RESPONSE(CodegenResponse.class), + SECURITY(CodegenSecurity.class); + + private final Class defaultImplementation; + + private CodegenModelType(Class defaultImplementation) { + this.defaultImplementation = defaultImplementation; + } + + public Class getDefaultImplementation() { + return defaultImplementation; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java new file mode 100644 index 00000000000..f7bd875848c --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java @@ -0,0 +1,32 @@ +package io.swagger.codegen; + +import io.swagger.models.*; + +import java.util.*; + +public class CodegenOperation { + public Boolean hasConsumes, hasProduces, hasParams, returnTypeIsPrimitive, + returnSimpleType, subresourceOperation, isMapContainer, isListContainer, + hasMore = Boolean.TRUE, isMultipart; + public String path, operationId, returnType, httpMethod, returnBaseType, + returnContainer, summary, notes, baseName, defaultResponse; + + public List> consumes, produces; + public CodegenParameter bodyParam; + public List allParams = new ArrayList(); + public List bodyParams = new ArrayList(); + public List pathParams = new ArrayList(); + public List queryParams = new ArrayList(); + public List headerParams = new ArrayList(); + public List formParams = new ArrayList(); + public List authMethods; + public List tags; + public List responses = new ArrayList(); + public final List responseHeaders = new ArrayList(); + public Set imports = new HashSet(); + public List> examples; + public ExternalDocs externalDocs; + + // legacy support + public String nickname; +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenParameter.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenParameter.java new file mode 100644 index 00000000000..f19809606d1 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenParameter.java @@ -0,0 +1,41 @@ +package io.swagger.codegen; + +public class CodegenParameter { + public Boolean isFormParam, isQueryParam, isPathParam, isHeaderParam, + isCookieParam, isBodyParam, isFile, notFile, hasMore, isContainer, secondaryParam; + public String baseName, paramName, dataType, collectionFormat, description, baseType, defaultValue; + public String jsonSchema; + + /** + * Determines whether this parameter is mandatory. If the parameter is in "path", + * this property is required and its value MUST be true. Otherwise, the property + * MAY be included and its default value is false. + */ + public Boolean required; + + public CodegenParameter copy() { + CodegenParameter output = new CodegenParameter(); + output.isFile = this.isFile; + output.notFile = this.notFile; + output.hasMore = this.hasMore; + output.isContainer = this.isContainer; + output.secondaryParam = this.secondaryParam; + output.baseName = this.baseName; + output.paramName = this.paramName; + output.dataType = this.dataType; + output.collectionFormat = this.collectionFormat; + output.description = this.description; + output.baseType = this.baseType; + output.isFormParam = this.isFormParam; + output.isQueryParam = this.isQueryParam; + output.isPathParam = this.isPathParam; + output.isHeaderParam = this.isHeaderParam; + output.isCookieParam = this.isCookieParam; + output.isBodyParam = this.isBodyParam; + output.required = this.required; + output.jsonSchema = this.jsonSchema; + output.defaultValue = this.defaultValue; + + return output; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java new file mode 100644 index 00000000000..407266add1f --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java @@ -0,0 +1,28 @@ +package io.swagger.codegen; + +import java.util.*; + +public class CodegenProperty { + public String baseName, complexType, getter, setter, description, datatype, datatypeWithEnum, + name, min, max, defaultValue, baseType, containerType; + + /** maxLength validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1 */ + public Integer maxLength; + /** minLength validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.2 */ + public Integer minLength; + /** pattern validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.3 */ + public String pattern; + /** A free-form property to include an example of an instance for this schema. */ + public String example; + + public String jsonSchema; + public Double minimum; + public Double maximum; + public Boolean exclusiveMinimum; + public Boolean exclusiveMaximum; + public Boolean hasMore = null, required = null, secondaryParam = null; + public Boolean isPrimitiveType, isContainer, isNotContainer; + public boolean isEnum; + public List _enum; + public Map allowableValues; +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenResponse.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenResponse.java new file mode 100644 index 00000000000..514ced65b63 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenResponse.java @@ -0,0 +1,21 @@ +package io.swagger.codegen; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CodegenResponse { + public String code, message; + public Boolean hasMore; + public List> examples; + public final List headers = new ArrayList(); + 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); } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenSecurity.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenSecurity.java new file mode 100644 index 00000000000..09e1a503191 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenSecurity.java @@ -0,0 +1,10 @@ +package io.swagger.codegen; + +public class CodegenSecurity { + public String name; + public String type; + public Boolean hasMore, isBasic, isOAuth, isApiKey; + // ApiKey specific + public String keyParamName; + public Boolean isKeyInQuery, isKeyInHeader; +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenType.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenType.java new file mode 100644 index 00000000000..b7c8aad9f1b --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenType.java @@ -0,0 +1,34 @@ +package io.swagger.codegen; + +import com.fasterxml.jackson.annotation.*; + +import java.util.Map; +import java.util.HashMap; + +public enum CodegenType { + CLIENT, SERVER, DOCUMENTATION, OTHER; + + private static Map names = new HashMap(); + + static { + names.put("client", CLIENT); + names.put("server", SERVER); + names.put("documentation", DOCUMENTATION); + names.put("other", OTHER); + } + + @JsonCreator + public static CodegenType forValue(String value) { + return names.get(value.toLowerCase()); + } + + @JsonValue + public String toValue() { + for (Map.Entry entry : names.entrySet()) { + if (entry.getValue() == this) + return entry.getKey(); + } + + return null; // or fail + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java new file mode 100644 index 00000000000..e342d07f66f --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java @@ -0,0 +1,1277 @@ +package io.swagger.codegen; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import io.swagger.codegen.examples.ExampleGenerator; +import io.swagger.models.ArrayModel; +import io.swagger.models.ComposedModel; +import io.swagger.models.Model; +import io.swagger.models.ModelImpl; +import io.swagger.models.Operation; +import io.swagger.models.RefModel; +import io.swagger.models.Response; +import io.swagger.models.Swagger; +import io.swagger.models.auth.ApiKeyAuthDefinition; +import io.swagger.models.auth.BasicAuthDefinition; +import io.swagger.models.auth.In; +import io.swagger.models.auth.SecuritySchemeDefinition; +import io.swagger.models.parameters.BodyParameter; +import io.swagger.models.parameters.CookieParameter; +import io.swagger.models.parameters.FormParameter; +import io.swagger.models.parameters.HeaderParameter; +import io.swagger.models.parameters.Parameter; +import io.swagger.models.parameters.PathParameter; +import io.swagger.models.parameters.QueryParameter; +import io.swagger.models.parameters.SerializableParameter; +import io.swagger.models.properties.AbstractNumericProperty; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.BooleanProperty; +import io.swagger.models.properties.DateProperty; +import io.swagger.models.properties.DateTimeProperty; +import io.swagger.models.properties.DecimalProperty; +import io.swagger.models.properties.DoubleProperty; +import io.swagger.models.properties.FloatProperty; +import io.swagger.models.properties.IntegerProperty; +import io.swagger.models.properties.LongProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.properties.PropertyBuilder; +import io.swagger.models.properties.RefProperty; +import io.swagger.models.properties.StringProperty; +import io.swagger.util.Json; + + +public class DefaultCodegen { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class); + + protected String outputFolder = ""; + protected Set defaultIncludes = new HashSet(); + protected Map typeMapping = new HashMap(); + protected Map instantiationTypes = new HashMap(); + protected Set reservedWords = new HashSet(); + protected Set languageSpecificPrimitives = new HashSet(); + protected Map importMapping = new HashMap(); + protected String modelPackage = "", apiPackage = "", fileSuffix; + protected Map apiTemplateFiles = new HashMap(); + protected Map modelTemplateFiles = new HashMap(); + protected String templateDir; + protected Map additionalProperties = new HashMap(); + protected List supportingFiles = new ArrayList(); + protected List cliOptions = new ArrayList(); + + public List cliOptions() { + return cliOptions; + } + + public void processOpts(){ + if(additionalProperties.containsKey("templateDir")) { + this.setTemplateDir((String)additionalProperties.get("templateDir")); + } + + if(additionalProperties.containsKey("modelPackage")) { + this.setModelPackage((String)additionalProperties.get("modelPackage")); + } + + if(additionalProperties.containsKey("apiPackage")) { + this.setApiPackage((String)additionalProperties.get("apiPackage")); + } + } + + // override with any special post-processing + public Map postProcessModels(Map objs) { + return objs; + } + + // override with any special post-processing + public Map postProcessOperations(Map objs) { + return objs; + } + + // override with any special post-processing + public Map postProcessSupportingFileData(Map objs) { + return objs; + } + + // override with any special handling of the entire swagger spec + public void processSwagger(Swagger swagger) {} + + // override with any special text escaping logic + public String escapeText(String input) { + if(input != null) { + String output = input.replaceAll("\n", "\\\\n"); + output = output.replace("\"", "\\\""); + return output; + } + return input; + } + + public Set defaultIncludes() { + return defaultIncludes; + } + public Map typeMapping() { + return typeMapping; + } + public Map instantiationTypes() { + return instantiationTypes; + } + public Set reservedWords() { + return reservedWords; + } + public Set languageSpecificPrimitives() { + return languageSpecificPrimitives; + } + public Map importMapping() { + return importMapping; + } + public String modelPackage() { + return modelPackage; + } + public String apiPackage() { + return apiPackage; + } + public String fileSuffix() { + return fileSuffix; + } + public String templateDir() { + return templateDir; + } + public Map apiTemplateFiles() { + return apiTemplateFiles; + } + public Map modelTemplateFiles() { + return modelTemplateFiles; + } + + public String apiFileFolder() { + return outputFolder + "/" + apiPackage().replace('.', File.separatorChar); + } + + public String modelFileFolder() { + return outputFolder + "/" + modelPackage().replace('.', File.separatorChar); + } + + public Map additionalProperties() { + return additionalProperties; + } + public List supportingFiles() { + return supportingFiles; + } + public String outputFolder() { + return outputFolder; + } + + public void setOutputDir(String dir) { + this.outputFolder = dir; + } + public String getOutputDir() { + return outputFolder(); + } + + public void setTemplateDir(String templateDir) { + this.templateDir = templateDir; + } + + public void setModelPackage(String modelPackage) { + this.modelPackage = modelPackage; + } + + public void setApiPackage(String apiPackage) { + this.apiPackage = apiPackage; + } + + public String toApiFilename(String name) { + return toApiName(name); + } + + public String toApiVarName(String name) { + return snakeCase(name); + } + + public String toModelFilename(String name) { + return initialCaps(name); + } + + public String toOperationId(String operationId) { return operationId; } + + public String toVarName(String name) { + if(reservedWords.contains(name)) + return escapeReservedWord(name); + else + return name; + } + + public String toParamName(String name) { + name = removeNonNameElementToCamelCase(name); + if(reservedWords.contains(name)) { + return escapeReservedWord(name); + } + 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"); + } + + public String toModelImport(String name) { + if("".equals(modelPackage())) + return name; + else + return modelPackage() + "." + name; + } + + public String toApiImport(String name) { + return apiPackage() + "." + name; + } + + public DefaultCodegen() { + defaultIncludes = new HashSet( + Arrays.asList("double", + "int", + "long", + "short", + "char", + "float", + "String", + "boolean", + "Boolean", + "Double", + "Void", + "Integer", + "Long", + "Float") + ); + + typeMapping = new HashMap(); + typeMapping.put("array", "List"); + typeMapping.put("map", "Map"); + typeMapping.put("List", "List"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("int", "Integer"); + typeMapping.put("float", "Float"); + typeMapping.put("number", "BigDecimal"); + typeMapping.put("DateTime", "Date"); + typeMapping.put("long", "Long"); + typeMapping.put("short", "Short"); + typeMapping.put("char", "String"); + typeMapping.put("double", "Double"); + typeMapping.put("object", "Object"); + typeMapping.put("integer", "Integer"); + + instantiationTypes = new HashMap(); + + reservedWords = new HashSet(); + + importMapping = new HashMap(); + importMapping.put("BigDecimal", "java.math.BigDecimal"); + importMapping.put("UUID", "java.util.UUID"); + importMapping.put("File", "java.io.File"); + importMapping.put("Date", "java.util.Date"); + importMapping.put("Timestamp", "java.sql.Timestamp"); + importMapping.put("Map", "java.util.Map"); + importMapping.put("HashMap", "java.util.HashMap"); + importMapping.put("Array", "java.util.List"); + importMapping.put("ArrayList", "java.util.ArrayList"); + importMapping.put("List", "java.util.*"); + importMapping.put("Set", "java.util.*"); + importMapping.put("DateTime", "org.joda.time.*"); + importMapping.put("LocalDateTime", "org.joda.time.*"); + importMapping.put("LocalDate", "org.joda.time.*"); + importMapping.put("LocalTime", "org.joda.time.*"); + + cliOptions.add(new CliOption("modelPackage", "package for generated models")); + cliOptions.add(new CliOption("apiPackage", "package for generated api classes")); + } + + + public String generateExamplePath(String path, Operation operation) { + StringBuilder sb = new StringBuilder(); + sb.append(path); + + if(operation.getParameters() != null) { + int count = 0; + + for(Parameter param : operation.getParameters()) { + if(param instanceof QueryParameter) { + StringBuilder paramPart = new StringBuilder(); + QueryParameter qp = (QueryParameter) param; + + if(count == 0) + paramPart.append("?"); + else + paramPart.append(","); + count += 1; + if(!param.getRequired()) + paramPart.append("["); + paramPart.append(param.getName()).append("="); + paramPart.append("{"); + if(qp.getCollectionFormat() != null) { + paramPart.append(param.getName() + "1"); + if("csv".equals(qp.getCollectionFormat())) + paramPart.append(","); + else if("pipes".equals(qp.getCollectionFormat())) + paramPart.append("|"); + else if("tsv".equals(qp.getCollectionFormat())) + paramPart.append("\t"); + else if("multi".equals(qp.getCollectionFormat())) { + paramPart.append("&").append(param.getName()).append("="); + paramPart.append(param.getName() + "2"); + } + } + else { + paramPart.append(param.getName()); + } + paramPart.append("}"); + if(!param.getRequired()) + paramPart.append("]"); + sb.append(paramPart.toString()); + } + } + } + + return sb.toString(); + } + + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return instantiationTypes.get("map") + ""; + } + 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 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) { + DoubleProperty dp = (DoubleProperty) p; + if(dp.getDefault() != null) { + return dp.getDefault().toString(); + } + return "null"; + } + else if (p instanceof FloatProperty) { + FloatProperty dp = (FloatProperty) p; + if(dp.getDefault() != null) { + return dp.getDefault().toString(); + } + return "null"; + } + else if (p instanceof IntegerProperty) { + IntegerProperty dp = (IntegerProperty) p; + if(dp.getDefault() != null) { + return dp.getDefault().toString(); + } + return "null"; + } + else if (p instanceof LongProperty) { + LongProperty dp = (LongProperty) p; + if(dp.getDefault() != null) { + return dp.getDefault().toString(); + } + return "null"; + } + else if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "new HashMap() "; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "new ArrayList<" + inner + ">() "; + } + else + return "null"; + } + + /** + * returns the swagger type for the property + **/ + public String getSwaggerType(Property p) { + String datatype = null; + if(p instanceof StringProperty) + datatype = "string"; + else if (p instanceof BooleanProperty) + datatype = "boolean"; + else if(p instanceof DateProperty) + datatype = "date"; + else if(p instanceof DateTimeProperty) + datatype = "DateTime"; + else if (p instanceof DoubleProperty) + datatype = "double"; + else if (p instanceof FloatProperty) + datatype = "float"; + else if (p instanceof IntegerProperty) + datatype = "integer"; + else if (p instanceof LongProperty) + datatype = "long"; + else if (p instanceof MapProperty) + datatype = "map"; + else if (p instanceof DecimalProperty) + datatype = "number"; + else if (p instanceof RefProperty) { + RefProperty r = (RefProperty)p; + datatype = r.get$ref(); + if(datatype.indexOf("#/definitions/") == 0) + datatype = datatype.substring("#/definitions/".length()); + } + else { + if(p != null) datatype = p.getType(); + } + return datatype; + } + + public String snakeCase(String name) { + return (name.length() > 0) ? (Character.toLowerCase(name.charAt(0)) + name.substring(1)) : ""; + } + + public String initialCaps(String name) { + return StringUtils.capitalize(name); + } + + public String getTypeDeclaration(String name) { + return name; + } + + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(p); + if(typeMapping.containsKey(swaggerType)) + return typeMapping.get(swaggerType); + return swaggerType; + } + + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultApi"; + return initialCaps(name) + "Api"; + } + + public String toModelName(String name) { + return initialCaps(name); + } + + public CodegenModel fromModel(String name, Model model) { + CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL); + if(reservedWords.contains(name)) + m.name = escapeReservedWord(name); + else + m.name = name; + m.description = escapeText(model.getDescription()); + m.classname = toModelName(name); + m.classVarName = toVarName(name); + m.modelJson = Json.pretty(model); + m.externalDocs = model.getExternalDocs(); + if(model instanceof ArrayModel) { + ArrayModel am = (ArrayModel) model; + ArrayProperty arrayProperty = new ArrayProperty(am.getItems()); + addParentContainer(m, name, arrayProperty); + } + else if (model instanceof RefModel) { + // TODO + } else if (model instanceof ComposedModel) { + final ComposedModel composed = (ComposedModel) model; + final RefModel parent = (RefModel) composed.getParent(); + final String parentModel = toModelName(parent.getSimpleRef()); + m.parent = parentModel; + addImport(m, parentModel); + final ModelImpl child = (ModelImpl) composed.getChild(); + addVars(m, child.getProperties(), child.getRequired()); + } else { + ModelImpl impl = (ModelImpl) model; + if(impl.getAdditionalProperties() != null) { + MapProperty mapProperty = new MapProperty(impl.getAdditionalProperties()); + addParentContainer(m, name, mapProperty); + } + addVars(m, impl.getProperties(), impl.getRequired()); + } + return m; + } + + public String getterAndSetterCapitalize(String name) { + if (name == null || name.length() == 0) { + return name; + } + + return camelize(toVarName(name)); + + } + + public CodegenProperty fromProperty(String name, Property p) { + if(p == null) { + LOGGER.error("unexpected missing property for name " + null); + return null; + } + CodegenProperty property = CodegenModelFactory.newInstance(CodegenModelType.PROPERTY); + + property.name = toVarName(name); + property.baseName = name; + property.description = escapeText(p.getDescription()); + property.getter = "get" + getterAndSetterCapitalize(name); + property.setter = "set" + getterAndSetterCapitalize(name); + property.example = p.getExample(); + property.defaultValue = toDefaultValue(p); + property.jsonSchema = Json.pretty(p); + + String type = getSwaggerType(p); + if(p instanceof AbstractNumericProperty) { + AbstractNumericProperty np = (AbstractNumericProperty) p; + property.minimum = np.getMinimum(); + property.maximum = np.getMaximum(); + property.exclusiveMinimum = np.getExclusiveMinimum(); + property.exclusiveMaximum = np.getExclusiveMaximum(); + + // legacy support + Map allowableValues = new HashMap(); + if(np.getMinimum() != null) + allowableValues.put("min", np.getMinimum()); + if(np.getMaximum() != null) + allowableValues.put("max", np.getMaximum()); + property.allowableValues = allowableValues; + } + + if(p instanceof StringProperty) { + StringProperty sp = (StringProperty) p; + property.maxLength = sp.getMaxLength(); + property.minLength = sp.getMinLength(); + property.pattern = sp.getPattern(); + if(sp.getEnum() != null) { + List _enum = sp.getEnum(); + property._enum = _enum; + property.isEnum = true; + + // legacy support + Map allowableValues = new HashMap(); + allowableValues.put("values", _enum); + property.allowableValues = allowableValues; + } + } + + property.datatype = getTypeDeclaration(p); + + // this can cause issues for clients which don't support enums + if(property.isEnum) + property.datatypeWithEnum = toEnumName(property); + else + property.datatypeWithEnum = property.datatype; + + property.baseType = getSwaggerType(p); + + if(p instanceof ArrayProperty) { + property.isContainer = true; + property.containerType = "array"; + ArrayProperty ap = (ArrayProperty) p; + CodegenProperty cp = fromProperty("inner", ap.getItems()); + if(cp == null) { + LOGGER.warn("skipping invalid property " + Json.pretty(p)); + } + else { + property.baseType = getSwaggerType(p); + if(!languageSpecificPrimitives.contains(cp.baseType)) + property.complexType = cp.baseType; + else + property.isPrimitiveType = true; + } + } + else if(p instanceof MapProperty) { + property.isContainer = true; + property.containerType = "map"; + MapProperty ap = (MapProperty) p; + CodegenProperty cp = fromProperty("inner", ap.getAdditionalProperties()); + + property.baseType = getSwaggerType(p); + if(!languageSpecificPrimitives.contains(cp.baseType)) + property.complexType = cp.baseType; + else + property.isPrimitiveType = true; + } + else { + setNonArrayMapProperty(property, type); + } + return property; + } + + protected void setNonArrayMapProperty(CodegenProperty property, String type) { + property.isNotContainer = true; + if(languageSpecificPrimitives().contains(type)) + property.isPrimitiveType = true; + else + property.complexType = property.baseType; + } + + private Response findMethodResponse(Map responses) { + + String code = null; + for(String responseCode : responses.keySet()) { + if (responseCode.startsWith("2") || responseCode.equals("default")) { + if (code == null || code.compareTo(responseCode) > 0) { + code = responseCode; + } + } + } + if (code == null) + return null; + return responses.get(code); + } + + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map definitions) { + CodegenOperation op = CodegenModelFactory.newInstance(CodegenModelType.OPERATION); + Set imports = new HashSet(); + + String operationId = operation.getOperationId(); + if(operationId == null) { + String tmpPath = path; + tmpPath = tmpPath.replaceAll("\\{", ""); + tmpPath = tmpPath.replaceAll("\\}", ""); + String[] parts = (tmpPath + "/" + httpMethod).split("/"); + StringBuilder builder = new StringBuilder(); + if("/".equals(tmpPath)) { + // must be root tmpPath + builder.append("root"); + } + for(int i = 0; i < parts.length; i++) { + String part = parts[i]; + if(part.length() > 0) { + if(builder.toString().length() == 0) + part = Character.toLowerCase(part.charAt(0)) + part.substring(1); + else + part = initialCaps(part); + builder.append(part); + } + } + operationId = builder.toString(); + LOGGER.warn("generated operationId " + operationId); + } + operationId = removeNonNameElementToCamelCase(operationId); + op.path = path; + op.operationId = toOperationId(operationId); + op.summary = escapeText(operation.getSummary()); + op.notes = escapeText(operation.getDescription()); + op.tags = operation.getTags(); + + if(operation.getConsumes() != null && operation.getConsumes().size() > 0) { + List> c = new ArrayList>(); + int count = 0; + for(String key: operation.getConsumes()) { + Map mediaType = new HashMap(); + mediaType.put("mediaType", key); + count += 1; + if (count < operation.getConsumes().size()) + mediaType.put("hasMore", "true"); + else + mediaType.put("hasMore", null); + c.add(mediaType); + } + op.consumes = c; + op.hasConsumes = true; + } + + if(operation.getProduces() != null && operation.getProduces().size() > 0) { + List> c = new ArrayList>(); + int count = 0; + for(String key: operation.getProduces()) { + Map mediaType = new HashMap(); + mediaType.put("mediaType", key); + count += 1; + if (count < operation.getProduces().size()) + mediaType.put("hasMore", "true"); + else + mediaType.put("hasMore", null); + c.add(mediaType); + } + op.produces = c; + op.hasProduces = true; + } + + if (operation.getResponses() != null && !operation.getResponses().isEmpty()) { + Response methodResponse = findMethodResponse(operation.getResponses()); + + for (Map.Entry entry : operation.getResponses().entrySet()) { + Response response = entry.getValue(); + CodegenResponse r = fromResponse(entry.getKey(), response); + r.hasMore = true; + if(r.baseType != null && + !defaultIncludes.contains(r.baseType) && + !languageSpecificPrimitives.contains(r.baseType)) + imports.add(r.baseType); + r.isDefault = response == methodResponse; + op.responses.add(r); + } + op.responses.get(op.responses.size() - 1).hasMore = false; + + if(methodResponse != null) { + if (methodResponse.getSchema() != null) { + CodegenProperty cm = fromProperty("response", methodResponse.getSchema()); + + Property responseProperty = methodResponse.getSchema(); + + if(responseProperty instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) responseProperty; + CodegenProperty innerProperty = fromProperty("response", ap.getItems()); + op.returnBaseType = innerProperty.baseType; + } + else { + if(cm.complexType != null) + op.returnBaseType = cm.complexType; + else + op.returnBaseType = cm.baseType; + } + op.examples = new ExampleGenerator(definitions).generate(methodResponse.getExamples(), operation.getProduces(), responseProperty); + op.defaultResponse = toDefaultValue(responseProperty); + op.returnType = cm.datatype; + if(cm.isContainer != null) { + op.returnContainer = cm.containerType; + if("map".equals(cm.containerType)) + op.isMapContainer = Boolean.TRUE; + else if ("list".equalsIgnoreCase(cm.containerType)) + op.isListContainer = Boolean.TRUE; + else if ("array".equalsIgnoreCase(cm.containerType)) + op.isListContainer = Boolean.TRUE; + } + else + op.returnSimpleType = true; + if (languageSpecificPrimitives().contains(op.returnBaseType) || op.returnBaseType == null) + op.returnTypeIsPrimitive = true; + } + addHeaders(methodResponse, op.responseHeaders); + } + } + + List parameters = operation.getParameters(); + CodegenParameter bodyParam = null; + List allParams = new ArrayList(); + List bodyParams = new ArrayList(); + List pathParams = new ArrayList(); + List queryParams = new ArrayList(); + List headerParams = new ArrayList(); + List cookieParams = new ArrayList(); + List formParams = new ArrayList(); + + if(parameters != null) { + for(Parameter param : parameters) { + CodegenParameter p = fromParameter(param, imports); + allParams.add(p); + if(param instanceof QueryParameter) { + p.isQueryParam = new Boolean(true); + queryParams.add(p.copy()); + } + else if(param instanceof PathParameter) { + p.required = true; + p.isPathParam = new Boolean(true); + pathParams.add(p.copy()); + } + else if(param instanceof HeaderParameter) { + p.isHeaderParam = new Boolean(true); + headerParams.add(p.copy()); + } + else if(param instanceof CookieParameter) { + p.isCookieParam = new Boolean(true); + cookieParams.add(p.copy()); + } + else if(param instanceof BodyParameter) { + p.isBodyParam = new Boolean(true); + bodyParam = p; + bodyParams.add(p.copy()); + } + else if(param instanceof FormParameter) { + if("file".equalsIgnoreCase(((FormParameter)param).getType())) + p.isFile = true; + else + p.notFile = true; + p.isFormParam = new Boolean(true); + formParams.add(p.copy()); + } + } + } + for(String i: imports) { + if(!defaultIncludes.contains(i) && !languageSpecificPrimitives.contains(i)){ + op.imports.add(i); + } + } + op.bodyParam = bodyParam; + op.httpMethod = httpMethod.toUpperCase(); + op.allParams = addHasMore(allParams); + op.bodyParams = addHasMore(bodyParams); + op.pathParams = addHasMore(pathParams); + op.queryParams = addHasMore(queryParams); + op.headerParams = addHasMore(headerParams); + // op.cookieParams = cookieParams; + op.formParams = addHasMore(formParams); + // legacy support + op.nickname = op.operationId; + + + if(op.allParams.size() > 0) + op.hasParams = true; + op.externalDocs = operation.getExternalDocs(); + + return op; + } + + public CodegenResponse fromResponse(String responseCode, Response response) { + CodegenResponse r = CodegenModelFactory.newInstance(CodegenModelType.RESPONSE); + if("default".equals(responseCode)) + r.code = "0"; + else + r.code = responseCode; + r.message = response.getDescription(); + r.schema = response.getSchema(); + r.examples = toExamples(response.getExamples()); + r.jsonSchema = Json.pretty(response); + addHeaders(response, r.headers); + + if (r.schema != null) { + Property responseProperty = response.getSchema(); + responseProperty.setRequired(true); + CodegenProperty cm = fromProperty("response", responseProperty); + + if(responseProperty instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) responseProperty; + CodegenProperty innerProperty = fromProperty("response", ap.getItems()); + r.baseType = innerProperty.baseType; + } + else { + if(cm.complexType != null) + r.baseType = cm.complexType; + else + r.baseType = cm.baseType; + } + r.dataType = cm.datatype; + if(cm.isContainer != null) { + r.simpleType = false; + r.containerType = cm.containerType; + r.isMapContainer = "map".equals(cm.containerType); + r.isListContainer = "list".equals(cm.containerType); + } + else + r.simpleType = true; + r.primitiveType = (r.baseType == null ||languageSpecificPrimitives().contains(r.baseType)); + } + if (r.baseType == null) { + r.isMapContainer = false; + r.isListContainer = false; + r.primitiveType = true; + r.simpleType = true; + } + return r; + } + + public CodegenParameter fromParameter(Parameter param, Set imports) { + CodegenParameter p = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); + p.baseName = param.getName(); + p.description = escapeText(param.getDescription()); + if(param.getRequired()) + p.required = param.getRequired(); + p.jsonSchema = Json.pretty(param); + + // move the defaultValue for headers, forms and params + if(param instanceof QueryParameter) { + p.defaultValue = ((QueryParameter)param).getDefaultValue(); + } else if(param instanceof HeaderParameter) { + p.defaultValue = ((HeaderParameter)param).getDefaultValue(); + } else if(param instanceof FormParameter) { + p.defaultValue = ((FormParameter)param).getDefaultValue(); + } + + if(param instanceof SerializableParameter) { + SerializableParameter qp = (SerializableParameter) param; + Property property = null; + String collectionFormat = null; + if("array".equals(qp.getType())) { + Property inner = qp.getItems(); + if(inner == null) { + LOGGER.warn("warning! No inner type supplied for array parameter \"" + qp.getName() + "\", using String"); + inner = new StringProperty().description("//TODO automatically added by swagger-codegen"); + } + property = new ArrayProperty(inner); + 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 + property = PropertyBuilder.build(qp.getType(), qp.getFormat(), null); + if(property == null) { + 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; + p.paramName = toParamName(qp.getName()); + + if(model.complexType != null) { + imports.add(model.complexType); + } + } + else { + BodyParameter bp = (BodyParameter) param; + Model model = bp.getSchema(); + + if(model instanceof ModelImpl) { + ModelImpl impl = (ModelImpl) model; + CodegenModel cm = fromModel(bp.getName(), impl); + if(cm.emptyVars != null && cm.emptyVars == false) { + p.dataType = getTypeDeclaration(cm.classname); + imports.add(p.dataType); + } + 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; + } + } + } + else if(model instanceof ArrayModel) { + // to use the built-in model parsing, we unwrap the ArrayModel + // and get a single property from it + ArrayModel impl = (ArrayModel) model; + 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); + } + imports.add(cp.baseType); + p.dataType = cp.datatype; + p.isContainer = true; + } + else{ + Model sub = bp.getSchema(); + if(sub instanceof RefModel) { + String name = ((RefModel)sub).getSimpleRef(); + if(typeMapping.containsKey(name)) + name = typeMapping.get(name); + else { + name = toModelName(name); + if(defaultIncludes.contains(name)) { + imports.add(name); + } + imports.add(name); + name = getTypeDeclaration(name); + } + p.dataType = name; + } + } + p.paramName = toParamName(bp.getName()); + } + return p; + } + + public List fromSecurity(Map schemes) { + if(schemes == null) + return null; + + List secs = new ArrayList(schemes.size()); + for (Iterator> it = schemes.entrySet().iterator(); it.hasNext();) { + final Map.Entry entry = it.next(); + final SecuritySchemeDefinition schemeDefinition = entry.getValue(); + + CodegenSecurity sec = CodegenModelFactory.newInstance(CodegenModelType.SECURITY); + sec.name = entry.getKey(); + sec.type = schemeDefinition.getType(); + + if (schemeDefinition instanceof ApiKeyAuthDefinition) { + final ApiKeyAuthDefinition apiKeyDefinition = (ApiKeyAuthDefinition) schemeDefinition; + sec.isBasic = sec.isOAuth = false; + sec.isApiKey = true; + sec.keyParamName = apiKeyDefinition.getName(); + sec.isKeyInHeader = apiKeyDefinition.getIn() == In.HEADER; + sec.isKeyInQuery = !sec.isKeyInHeader; + } else { + sec.isKeyInHeader = sec.isKeyInQuery = sec.isApiKey = false; + sec.isBasic = schemeDefinition instanceof BasicAuthDefinition; + sec.isOAuth = !sec.isBasic; + } + + sec.hasMore = it.hasNext(); + secs.add(sec); + } + return secs; + } + + protected List> toExamples(Map examples) { + if(examples == null) + return null; + + final List> output = new ArrayList>(examples.size()); + for(Map.Entry entry : examples.entrySet()) { + final Map kv = new HashMap(); + kv.put("contentType", entry.getKey()); + kv.put("example", entry.getValue()); + output.add(kv); + } + return output; + } + + private void addHeaders(Response response, List target) { + if (response.getHeaders() != null) { + for (Map.Entry headers : response.getHeaders().entrySet()) { + target.add(fromProperty(headers.getKey(), headers.getValue())); + } + } + } + + private List addHasMore(List objs) { + if(objs != null) { + for(int i = 0; i < objs.size(); i++) { + if(i > 0) + objs.get(i).secondaryParam = new Boolean(true); + if(i < objs.size() - 1) + objs.get(i).hasMore = new Boolean(true); + } + } + return objs; + } + + private Map addHasMore(Map objs) { + if(objs != null) { + for(int i = 0; i < objs.size() - 1; i++) { + if(i > 0) + objs.put("secondaryParam", new Boolean(true)); + if(i < objs.size() - 1) + objs.put("hasMore", true); + } + } + return objs; + } + + + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + List opList = operations.get(tag); + if(opList == null) { + opList = new ArrayList(); + operations.put(tag, opList); + } + opList.add(co); + co.baseName = tag; + } + + private void addParentContainer(CodegenModel m, String name, Property property) { + final CodegenProperty tmp = fromProperty(name, property); + addImport(m, tmp.complexType); + m.parent = toInstantiationType(property); + final String containerType = tmp.containerType; + final String instantiationType = instantiationTypes.get(containerType); + if (instantiationType != null) { + addImport(m, instantiationType); + } + final String mappedType = typeMapping.get(containerType); + if (mappedType != null) { + addImport(m, mappedType); + } + } + + private void addImport(CodegenModel m, String type) { + if (type != null && !languageSpecificPrimitives.contains(type) && !defaultIncludes.contains(type)) { + m.imports.add(type); + } + } + + private void addVars(CodegenModel m, Map properties, Collection required) { + if (properties != null && properties.size() > 0) { + m.hasVars = true; + m.hasEnums = false; + final int totalCount = properties.size(); + final Set mandatory = required == null ? Collections. emptySet() : new HashSet(required); + int count = 0; + for (Map.Entry entry : properties.entrySet()) { + final String key = entry.getKey(); + final Property prop = entry.getValue(); + + if (prop == null) { + LOGGER.warn("null property for " + key); + } else { + final CodegenProperty cp = fromProperty(key, prop); + cp.required = mandatory.contains(key) ? true : null; + if (cp.isEnum) { + m.hasEnums = true; + } + count += 1; + if (count != totalCount) + cp.hasMore = true; + if (cp.isContainer != null) { + addImport(m, typeMapping.get("array")); + } + addImport(m, cp.baseType); + addImport(m, cp.complexType); + m.vars.add(cp); + } + } + } else { + m.emptyVars = true; + } + } + + /* underscore and camelize are copied from Twitter elephant bird + * https://github.com/twitter/elephant-bird/blob/master/core/src/main/java/com/twitter/elephantbird/util/Strings.java + */ + + /** + * Underscore the given word. + * @param word The word + * @return The underscored version of the word + */ + public static String underscore(String word) { + String firstPattern = "([A-Z]+)([A-Z][a-z])"; + String secondPattern = "([a-z\\d])([A-Z])"; + String replacementPattern = "$1_$2"; + // Replace package separator with slash. + word = word.replaceAll("\\.", "/"); + // Replace $ with two underscores for inner classes. + word = word.replaceAll("\\$", "__"); + // Replace capital letter with _ plus lowercase letter. + word = word.replaceAll(firstPattern, replacementPattern); + word = word.replaceAll(secondPattern, replacementPattern); + word = word.replace('-', '_'); + word = word.toLowerCase(); + return word; + } + + /** + * Remove characters not suitable for variable or method name from the input and camelize it + * @param name + * @return + */ + public String removeNonNameElementToCamelCase(String name) { + String nonNameElementPattern = "[-_:;#]"; + name = StringUtils.join(Lists.transform(Lists.newArrayList(name.split(nonNameElementPattern)), new Function() { + @Nullable + @Override + public String apply(String input) { + return StringUtils.capitalize(input); + } + }), ""); + if (name.length() > 0) { + name = name.substring(0, 1).toLowerCase() + name.substring(1); + } + return name; + } + + public static String camelize(String word) { + return camelize(word, false); + } + + public static String camelize(String word, boolean lowercaseFirstLetter) { + // Replace all slashes with dots (package separator) + Pattern p = Pattern.compile("\\/(.?)"); + Matcher m = p.matcher(word); + while (m.find()) { + word = m.replaceFirst("." + m.group(1)/*.toUpperCase()*/); + m = p.matcher(word); + } + + // case out dots + String[] parts = word.split("\\."); + StringBuilder f = new StringBuilder(); + for(String z : parts) { + if(z.length() > 0) + f.append(Character.toUpperCase(z.charAt(0))).append(z.substring(1)); + } + word = f.toString(); + + m = p.matcher(word); + while (m.find()) { + word = m.replaceFirst("" + Character.toUpperCase(m.group(1).charAt(0)) + m.group(1).substring(1)/*.toUpperCase()*/); + m = p.matcher(word); + } + + // Uppercase the class name. + p = Pattern.compile("(\\.?)(\\w)([^\\.]*)$"); + m = p.matcher(word); + if (m.find()) { + String rep = m.group(1) + m.group(2).toUpperCase() + m.group(3); + rep = rep.replaceAll("\\$", "\\\\\\$"); + word = m.replaceAll(rep); + } + + // Replace two underscores with $ to support inner classes. + p = Pattern.compile("(__)(.)"); + m = p.matcher(word); + while (m.find()) { + word = m.replaceFirst("\\$" + m.group(2).toUpperCase()); + m = p.matcher(word); + } + + // Remove all underscores + p = Pattern.compile("(_)(.)"); + m = p.matcher(word); + while (m.find()) { + word = m.replaceFirst(m.group(2).toUpperCase()); + m = p.matcher(word); + } + + if (lowercaseFirstLetter) { + word = word.substring(0, 1).toLowerCase() + word.substring(1); + } + + return word; + } + + + public String apiFilename(String templateName, String tag) + { + String suffix = apiTemplateFiles().get(templateName); + return apiFileFolder() + File.separator + toApiFilename(tag) + suffix; + } + + public boolean shouldOverwrite( String filename ){ + return true; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java new file mode 100644 index 00000000000..1f9da14119d --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java @@ -0,0 +1,487 @@ +package io.swagger.codegen; + +import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Template; +import io.swagger.models.Contact; +import io.swagger.models.Info; +import io.swagger.models.License; +import io.swagger.models.Model; +import io.swagger.models.Operation; +import io.swagger.models.Path; +import io.swagger.models.Swagger; +import io.swagger.models.auth.SecuritySchemeDefinition; +import io.swagger.util.Json; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.Reader; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.apache.commons.lang3.StringUtils.capitalize; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; + +public class DefaultGenerator extends AbstractGenerator implements Generator { + protected CodegenConfig config; + protected ClientOptInput opts = null; + protected Swagger swagger = null; + + public Generator opts(ClientOptInput opts) { + this.opts = opts; + + this.swagger = opts.getSwagger(); + this.config = opts.getConfig(); + this.config.additionalProperties().putAll(opts.getOpts().getProperties()); + + return this; + } + + public List generate() { + if (swagger == null || config == null) { + throw new RuntimeException("missing swagger input or config!"); + } + if (System.getProperty("debugSwagger") != null) { + Json.prettyPrint(swagger); + } + List files = new ArrayList(); + try { + config.processOpts(); + if (swagger.getInfo() != null) { + Info info = swagger.getInfo(); + if (info.getTitle() != null) { + config.additionalProperties().put("appName", info.getTitle()); + } + if (info.getVersion() != null) { + config.additionalProperties().put("appVersion", info.getVersion()); + } + if (info.getDescription() != null) { + config.additionalProperties().put("appDescription", + config.escapeText(info.getDescription())); + } + if (info.getContact() != null) { + Contact contact = info.getContact(); + config.additionalProperties().put("infoUrl", contact.getUrl()); + if (contact.getEmail() != null) { + config.additionalProperties().put("infoEmail", contact.getEmail()); + } + } + if (info.getLicense() != null) { + License license = info.getLicense(); + if (license.getName() != null) { + config.additionalProperties().put("licenseInfo", license.getName()); + } + if (license.getUrl() != null) { + config.additionalProperties().put("licenseUrl", license.getUrl()); + } + } + if (info.getVersion() != null) { + config.additionalProperties().put("version", info.getVersion()); + } + } + + StringBuilder hostBuilder = new StringBuilder(); + String scheme; + if (swagger.getSchemes() != null && swagger.getSchemes().size() > 0) { + scheme = swagger.getSchemes().get(0).toValue(); + } else { + scheme = "https"; + } + hostBuilder.append(scheme); + hostBuilder.append("://"); + if (swagger.getHost() != null) { + hostBuilder.append(swagger.getHost()); + } else { + hostBuilder.append("localhost"); + } + if (swagger.getBasePath() != null) { + hostBuilder.append(swagger.getBasePath()); + } else { + hostBuilder.append("/"); + } + String contextPath = swagger.getBasePath() == null ? "/" : swagger.getBasePath(); + String basePath = hostBuilder.toString(); + + + List allOperations = new ArrayList(); + List allModels = new ArrayList(); + + // models + Map definitions = swagger.getDefinitions(); + if (definitions != null) { + for (String name : definitions.keySet()) { + Model model = definitions.get(name); + Map modelMap = new HashMap(); + modelMap.put(name, model); + Map models = processModels(config, modelMap); + models.putAll(config.additionalProperties()); + + allModels.add(((List) models.get("models")).get(0)); + + for (String templateName : config.modelTemplateFiles().keySet()) { + String suffix = config.modelTemplateFiles().get(templateName); + String filename = config.modelFileFolder() + File.separator + config.toModelFilename(name) + suffix; + String template = readTemplate(config.templateDir() + File.separator + templateName); + Template tmpl = Mustache.compiler() + .withLoader(new Mustache.TemplateLoader() { + public Reader getTemplate(String name) { + return getTemplateReader(config.templateDir() + File.separator + name + ".mustache"); + } + }) + .defaultValue("") + .compile(template); + writeToFile(filename, tmpl.execute(models)); + files.add(new File(filename)); + } + } + } + if (System.getProperty("debugModels") != null) { + System.out.println("############ Model info ############"); + Json.prettyPrint(allModels); + } + + // apis + Map> paths = processPaths(swagger.getPaths()); + for (String tag : paths.keySet()) { + List ops = paths.get(tag); + Map operation = processOperations(config, tag, ops); + + operation.put("basePath", basePath); + operation.put("contextPath", contextPath); + operation.put("baseName", tag); + operation.put("modelPackage", config.modelPackage()); + operation.putAll(config.additionalProperties()); + operation.put("classname", config.toApiName(tag)); + operation.put("classVarName", config.toApiVarName(tag)); + operation.put("importPath", config.toApiImport(tag)); + + processMimeTypes(swagger.getConsumes(), operation, "consumes"); + processMimeTypes(swagger.getProduces(), operation, "produces"); + + allOperations.add(new HashMap(operation)); + for (int i = 0; i < allOperations.size(); i++) { + Map oo = (Map) allOperations.get(i); + if (i < (allOperations.size() - 1)) { + oo.put("hasMore", "true"); + } + } + + for (String templateName : config.apiTemplateFiles().keySet()) { + + String filename = config.apiFilename( templateName, tag ); + if( new File( filename ).exists() && !config.shouldOverwrite( filename )){ + continue; + } + + String template = readTemplate(config.templateDir() + File.separator + templateName); + Template tmpl = Mustache.compiler() + .withLoader(new Mustache.TemplateLoader() { + public Reader getTemplate(String name) { + return getTemplateReader(config.templateDir() + File.separator + name + ".mustache"); + } + }) + .defaultValue("") + .compile(template); + + writeToFile(filename, tmpl.execute(operation)); + files.add(new File(filename)); + } + } + if (System.getProperty("debugOperations") != null) { + System.out.println("############ Operation info ############"); + Json.prettyPrint(allOperations); + } + + // supporting files + Map bundle = new HashMap(); + bundle.putAll(config.additionalProperties()); + bundle.put("apiPackage", config.apiPackage()); + + Map apis = new HashMap(); + apis.put("apis", allOperations); + if (swagger.getHost() != null) { + bundle.put("host", swagger.getHost()); + } + bundle.put("basePath", basePath); + bundle.put("scheme", scheme); + bundle.put("contextPath", contextPath); + bundle.put("apiInfo", apis); + bundle.put("models", allModels); + bundle.put("apiFolder", config.apiPackage().replace('.', File.separatorChar)); + bundle.put("modelPackage", config.modelPackage()); + bundle.put("authMethods", config.fromSecurity(swagger.getSecurityDefinitions())); + if (swagger.getExternalDocs() != null) { + bundle.put("externalDocs", swagger.getExternalDocs()); + } + for (int i = 0; i < allModels.size() - 1; i++) { + HashMap cm = (HashMap) allModels.get(i); + CodegenModel m = cm.get("model"); + m.hasMoreModels = true; + } + + config.postProcessSupportingFileData(bundle); + + if (System.getProperty("debugSupportingFiles") != null) { + System.out.println("############ Supporting file info ############"); + Json.prettyPrint(bundle); + } + + for (SupportingFile support : config.supportingFiles()) { + String outputFolder = config.outputFolder(); + if (isNotEmpty(support.folder)) { + outputFolder += File.separator + support.folder; + } + File of = new File(outputFolder); + if (!of.isDirectory()) { + of.mkdirs(); + } + String outputFilename = outputFolder + File.separator + support.destinationFilename; + + if (support.templateFile.endsWith("mustache")) { + String template = readTemplate(config.templateDir() + File.separator + support.templateFile); + Template tmpl = Mustache.compiler() + .withLoader(new Mustache.TemplateLoader() { + public Reader getTemplate(String name) { + return getTemplateReader(config.templateDir() + File.separator + name + ".mustache"); + } + }) + .defaultValue("") + .compile(template); + + writeToFile(outputFilename, tmpl.execute(bundle)); + files.add(new File(outputFilename)); + } else { + InputStream in = null; + + try { + in = new FileInputStream(config.templateDir() + File.separator + support.templateFile); + } + catch (Exception e) { + // continue + } + if(in == null) { + in = this.getClass().getClassLoader().getResourceAsStream(config.templateDir() + File.separator + support.templateFile); + } + File outputFile = new File(outputFilename); + OutputStream out = new FileOutputStream(outputFile, false); + if(in != null && out != null) + IOUtils.copy(in,out); + else { + if(in == null) + System.out.println("can't open " + config.templateDir() + File.separator + support.templateFile + " for input"); + if(out == null) + System.out.println("can't open " + outputFile + " for output"); + } + + files.add(outputFile); + } + } + + config.processSwagger(swagger); + } catch (Exception e) { + e.printStackTrace(); + } + return files; + } + + private void processMimeTypes(List mimeTypeList, Map operation, String source) { + if(mimeTypeList != null && mimeTypeList.size() > 0) { + List> c = new ArrayList>(); + int count = 0; + for(String key: mimeTypeList) { + Map mediaType = new HashMap(); + mediaType.put("mediaType", key); + count += 1; + if (count < mimeTypeList.size()) { + mediaType.put("hasMore", "true"); + } + else { + mediaType.put("hasMore", null); + } + c.add(mediaType); + } + operation.put(source, c); + String flagFieldName = "has" + source.substring(0, 1).toUpperCase() + source.substring(1); + operation.put(flagFieldName, true); + } + } + + public Map> processPaths(Map paths) { + Map> ops = new HashMap>(); + + for (String resourcePath : paths.keySet()) { + Path path = paths.get(resourcePath); + processOperation(resourcePath, "get", path.getGet(), ops); + processOperation(resourcePath, "put", path.getPut(), ops); + processOperation(resourcePath, "post", path.getPost(), ops); + processOperation(resourcePath, "delete", path.getDelete(), ops); + processOperation(resourcePath, "patch", path.getPatch(), ops); + processOperation(resourcePath, "options", path.getOptions(), ops); + } + return ops; + } + + public SecuritySchemeDefinition fromSecurity(String name) { + Map map = swagger.getSecurityDefinitions(); + if (map == null) { + return null; + } + return map.get(name); + } + + + public void processOperation(String resourcePath, String httpMethod, Operation operation, Map> operations) { + if (operation != null) { + List tags = operation.getTags(); + if (tags == null) { + tags = new ArrayList(); + tags.add("default"); + } + + for (String tag : tags) { + CodegenOperation co = config.fromOperation(resourcePath, httpMethod, operation, swagger.getDefinitions()); + co.tags = new ArrayList(); + co.tags.add(sanitizeTag(tag)); + config.addOperationToGroup(sanitizeTag(tag), resourcePath, operation, co, operations); + + List>> securities = operation.getSecurity(); + if (securities == null) { + continue; + } + Map authMethods = new HashMap(); + for (Map> security : securities) { + if (security.size() != 1) { + //Not sure what to do + continue; + } + String securityName = security.keySet().iterator().next(); + SecuritySchemeDefinition securityDefinition = fromSecurity(securityName); + if (securityDefinition != null) { + authMethods.put(securityName, securityDefinition); + } + } + if (!authMethods.isEmpty()) { + co.authMethods = config.fromSecurity(authMethods); + } + } + } + } + + protected String sanitizeTag(String tag) { + // remove spaces and make strong case + String[] parts = tag.split(" "); + StringBuilder buf = new StringBuilder(); + for (String part : parts) { + if (isNotEmpty(part)) { + buf.append(capitalize(part)); + } + } + return buf.toString().replaceAll("[^a-zA-Z ]", ""); + } + + public Map processOperations(CodegenConfig config, String tag, List ops) { + Map operations = new HashMap(); + Map objs = new HashMap(); + objs.put("classname", config.toApiName(tag)); + + // check for operationId uniqueness + Set opIds = new HashSet(); + int counter = 0; + for(CodegenOperation op : ops) { + String opId = op.nickname; + if(opIds.contains(opId)) { + counter ++; + op.nickname += "_" + counter; + } + opIds.add(opId); + } + objs.put("operation", ops); + + operations.put("operations", objs); + operations.put("package", config.apiPackage()); + + + Set allImports = new LinkedHashSet(); + for (CodegenOperation op : ops) { + allImports.addAll(op.imports); + } + + List> imports = new ArrayList>(); + for (String nextImport : allImports) { + Map im = new LinkedHashMap(); + String mapping = config.importMapping().get(nextImport); + if (mapping == null) { + mapping = config.toModelImport(nextImport); + } + if (mapping != null) { + im.put("import", mapping); + imports.add(im); + } + } + + operations.put("imports", imports); + config.postProcessOperations(operations); + if (objs.size() > 0) { + List os = (List) objs.get("operation"); + + if (os != null && os.size() > 0) { + CodegenOperation op = os.get(os.size() - 1); + op.hasMore = null; + } + } + return operations; + } + + public Map processModels(CodegenConfig config, Map definitions) { + Map objs = new HashMap(); + objs.put("package", config.modelPackage()); + List models = new ArrayList(); + Set allImports = new LinkedHashSet(); + for (String key : definitions.keySet()) { + Model mm = definitions.get(key); + CodegenModel cm = config.fromModel(key, mm); + Map mo = new HashMap(); + mo.put("model", cm); + mo.put("importPath", config.toModelImport(key)); + models.add(mo); + allImports.addAll(cm.imports); + } + objs.put("models", models); + + List> imports = new ArrayList>(); + for (String nextImport : allImports) { + Map im = new LinkedHashMap(); + String mapping = config.importMapping().get(nextImport); + if (mapping == null) { + mapping = config.toModelImport(nextImport); + } + if (mapping != null && !config.defaultIncludes().contains(mapping)) { + im.put("import", mapping); + imports.add(im); + } + // add instantiation types + mapping = config.instantiationTypes().get(nextImport); + if (mapping != null && !config.defaultIncludes().contains(mapping)) { + im.put("import", mapping); + imports.add(im); + } + } + + objs.put("imports", imports); + config.postProcessModels(objs); + + return objs; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/Generator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/Generator.java new file mode 100644 index 00000000000..cf44f46e637 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/Generator.java @@ -0,0 +1,11 @@ +package io.swagger.codegen; + +import io.swagger.models.Swagger; + +import java.io.File; +import java.util.List; + +public interface Generator { + Generator opts(ClientOptInput opts); + List generate(); +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/MetaGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/MetaGenerator.java new file mode 100644 index 00000000000..a6fdd93f271 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/MetaGenerator.java @@ -0,0 +1,185 @@ +package io.swagger.codegen; + +import io.swagger.codegen.languages.*; +import io.swagger.models.Swagger; +import io.swagger.models.auth.AuthorizationValue; +import io.swagger.util.*; + +import io.swagger.parser.SwaggerParser; + +import com.samskivert.mustache.*; + +import org.apache.commons.cli.*; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.Reader; +import java.util.*; + +/** + * @deprecated use instead {@link io.swagger.codegen.DefaultGenerator} + * or cli interface from https://github.com/swagger-api/swagger-codegen/pull/547 + */ +@Deprecated +public class MetaGenerator extends AbstractGenerator { + static Map configs = new HashMap(); + static String configString; + static { + List extensions = getExtensions(); + StringBuilder sb = new StringBuilder(); + + for(CodegenConfig config : extensions) { + if(sb.toString().length() != 0) + sb.append(", "); + sb.append(config.getName()); + configs.put(config.getName(), config); + configString = sb.toString(); + } + } + + public static void main(String[] args) { + new MetaGenerator().generate(args); + } + + protected void generate(String[] args) { + StringBuilder sb = new StringBuilder(); + String targetLanguage = null; + String outputFolder = null; + String name = null; + String targetPackage = "io.swagger.codegen"; + final String templateDir = "codegen"; + + Options options = new Options(); + options.addOption("h", "help", false, "shows this message"); + options.addOption("l", "lang", false, "client language to generate.\nAvailable languages include:\n\t[" + configString + "]"); + options.addOption("o", "output", true, "where to write the generated files"); + options.addOption("n", "name", true, "the human-readable name of the generator"); + options.addOption("p", "package", true, "the package to put the main class into (defaults to io.swagger.codegen"); + + ClientOptInput clientOptInput = new ClientOptInput(); + Swagger swagger = null; + CommandLine cmd = null; + try { + CommandLineParser parser = new BasicParser(); + + cmd = parser.parse(options, args); + if (cmd.hasOption("h")) { + usage(options); + return; + } + if (cmd.hasOption("n")) + name = cmd.getOptionValue("n"); + else { + System.out.println("name is required"); + usage(options); + return; + } + if (cmd.hasOption("l")) + targetLanguage = cmd.getOptionValue("l"); + if (cmd.hasOption("p")) + targetPackage = cmd.getOptionValue("p"); + if (cmd.hasOption("o")) + outputFolder = cmd.getOptionValue("o"); + else { + System.out.println("output folder is required"); + usage(options); + return; + } + } + catch (Exception e) { + usage(options); + return; + } + System.out.println("writing to folder " + outputFolder); + File outputFolderLocation = new File(outputFolder); + if(!outputFolderLocation.exists()) + outputFolderLocation.mkdirs(); + File sourceFolder = new File(outputFolder + File.separator + "src/main/java/" + targetPackage.replace('.', File.separatorChar)); + if(!sourceFolder.exists()) + sourceFolder.mkdirs(); + File resourcesFolder = new File(outputFolder + File.separator + "src/main/resources/META-INF/services"); + if(!resourcesFolder.exists()) + resourcesFolder.mkdirs(); + + String mainClass = Character.toUpperCase(name.charAt(0)) + name.substring(1) + "Generator"; + + List supportingFiles = new ArrayList(); + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("generatorClass.mustache", + "src/main/java/" + File.separator + targetPackage.replace('.', File.separatorChar), + mainClass + ".java")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("api.template", "src/main/resources" + File.separator + name, "api.mustache")); + supportingFiles.add(new SupportingFile("model.template", "src/main/resources" + File.separator + name, "model.mustache")); + + supportingFiles.add(new SupportingFile("services.mustache", "src/main/resources/META-INF/services", "io.swagger.codegen.CodegenConfig")); + + List files = new ArrayList(); + + Map data = new HashMap(); + data.put("generatorPackage", targetPackage); + data.put("generatorClass", mainClass); + data.put("name", name); + data.put("fullyQualifiedGeneratorClass", targetPackage + "." + mainClass); + + for(SupportingFile support : supportingFiles) { + try { + String destinationFolder = outputFolder; + if(support.folder != null && !"".equals(support.folder)) + destinationFolder += File.separator + support.folder; + File of = new File(destinationFolder); + if(!of.isDirectory()) + of.mkdirs(); + String outputFilename = destinationFolder + File.separator + support.destinationFilename; + + if(support.templateFile.endsWith("mustache")) { + String template = readTemplate(templateDir + File.separator + support.templateFile); + Template tmpl = Mustache.compiler() + .withLoader(new Mustache.TemplateLoader() { + public Reader getTemplate (String name) { + return getTemplateReader(templateDir + File.separator + name + ".mustache"); + }; + }) + .defaultValue("") + .compile(template); + + writeToFile(outputFilename, tmpl.execute(data)); + files.add(new File(outputFilename)); + } + else { + String template = readTemplate(templateDir + File.separator + support.templateFile); + FileUtils.writeStringToFile(new File(outputFilename), template); + System.out.println("copying file to " + outputFilename); + files.add(new File(outputFilename)); + } + } + catch (java.io.IOException e) { + e.printStackTrace(); + } + } + } + + public static List getExtensions() { + ServiceLoader loader = ServiceLoader.load(CodegenConfig.class); + List output = new ArrayList(); + Iterator itr = loader.iterator(); + while(itr.hasNext()) { + output.add(itr.next()); + } + return output; + } + + static void usage(Options options) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp( "MetaGenerator. Generator for creating a new template set " + + "and configuration for Codegen. The output will be based on the language you " + + "specify, and includes default templates to include.", options ); + } + + public static CodegenConfig getConfig(String name) { + if(configs.containsKey(name)) { + return configs.get(name); + } + return null; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/SupportingFile.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/SupportingFile.java new file mode 100644 index 00000000000..133a6259f24 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/SupportingFile.java @@ -0,0 +1,13 @@ +package io.swagger.codegen; + +public class SupportingFile { + public String templateFile; + public String folder; + public String destinationFilename; + + public SupportingFile(String templateFile, String folder, String destinationFilename) { + this.templateFile = templateFile; + this.folder = folder; + this.destinationFilename = destinationFilename; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/auth/AuthMethod.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/auth/AuthMethod.java new file mode 100644 index 00000000000..94b43f59888 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/auth/AuthMethod.java @@ -0,0 +1,6 @@ +package io.swagger.codegen.auth; + +public interface AuthMethod { + String getType(); + void setType(String type); +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/ExampleGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/ExampleGenerator.java new file mode 100644 index 00000000000..d6ee8ac642c --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/ExampleGenerator.java @@ -0,0 +1,175 @@ +package io.swagger.codegen.examples; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import io.swagger.models.Model; +import io.swagger.models.ModelImpl; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.BooleanProperty; +import io.swagger.models.properties.DateProperty; +import io.swagger.models.properties.DateTimeProperty; +import io.swagger.models.properties.DecimalProperty; +import io.swagger.models.properties.DoubleProperty; +import io.swagger.models.properties.FileProperty; +import io.swagger.models.properties.FloatProperty; +import io.swagger.models.properties.IntegerProperty; +import io.swagger.models.properties.LongProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.ObjectProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.properties.RefProperty; +import io.swagger.models.properties.StringProperty; +import io.swagger.models.properties.UUIDProperty; +import io.swagger.util.Json; + +public class ExampleGenerator { + protected Map examples; + + public ExampleGenerator(Map examples) { + this.examples = examples; + } + + public List> generate(Map examples, List mediaTypes, Property property) { + List> output = new ArrayList>(); + Set processedModels = new HashSet(); + if(examples == null ) { + if(mediaTypes == null) { + // assume application/json for this + mediaTypes = Arrays.asList("application/json"); + } + for(String mediaType : mediaTypes) { + Map kv = new HashMap(); + kv.put("contentType", mediaType); + if(property != null && mediaType.startsWith("application/json")) { + String example = Json.pretty(resolvePropertyToExample(mediaType, property, processedModels)); + + if(example != null) { + kv.put("example", example); + output.add(kv); + } + } + else if(property != null && mediaType.startsWith("application/xml")) { + String example = new XmlExampleGenerator(this.examples).toXml(property); + if(example != null) { + kv.put("example", example); + output.add(kv); + } + } + } + } + else { + for(Map.Entry entry: examples.entrySet()) { + final Map kv = new HashMap(); + kv.put("contentType", entry.getKey()); + kv.put("example", Json.pretty(entry.getValue())); + output.add(kv); + } + } + if(output.size() == 0) { + Map kv = new HashMap(); + kv.put("output", "none"); + output.add(kv); + } + return output; + } + + protected Object resolvePropertyToExample(String mediaType, Property property, Set processedModels) { + if(property.getExample() != null) { + return property.getExample(); + } + else if(property instanceof StringProperty) { + return "aeiou"; + } + else if(property instanceof BooleanProperty) { + return Boolean.TRUE; + } + else if(property instanceof ArrayProperty) { + Property innerType = ((ArrayProperty)property).getItems(); + if(innerType != null) { + Object[] output = new Object[]{ + resolvePropertyToExample(mediaType, innerType, processedModels) + }; + return output; + } + } + else if(property instanceof DateProperty) { + return new java.util.Date(System.currentTimeMillis()); + } + else if(property instanceof DateTimeProperty) { + return new java.util.Date(System.currentTimeMillis()); + } + else if(property instanceof DecimalProperty) { + return new BigDecimal(1.3579); + } + else if(property instanceof DoubleProperty) { + return new Double(3.149); + } + else if(property instanceof FileProperty) { + return ""; // TODO + } + else if(property instanceof FloatProperty) { + return new Float(1.23); + } + else if(property instanceof IntegerProperty) { + return new Integer(123); + } + else if(property instanceof LongProperty) { + return new Long(123456789); + } + else if(property instanceof MapProperty) { + Map mp = new HashMap(); + if(property.getName() != null) { + mp.put(property.getName(), + resolvePropertyToExample(mediaType, ((MapProperty)property).getAdditionalProperties(), processedModels)); + } + else { + mp.put("key", + resolvePropertyToExample(mediaType, ((MapProperty)property).getAdditionalProperties(), processedModels)); + } + return mp; + } + else if(property instanceof ObjectProperty) { + return "{}"; + } + else if(property instanceof RefProperty) { + String simpleName = ((RefProperty)property).getSimpleRef(); + Model model = examples.get(simpleName); + if(model != null) + return resolveModelToExample(simpleName, mediaType, model, processedModels); + } + else if(property instanceof UUIDProperty) { + return "046b6c7f-0b8a-43b9-b35d-6489e6daee91"; + } + + return ""; + } + + public Object resolveModelToExample(String name, String mediaType, Model model, Set processedModels) { + if(processedModels.contains(name)) { + return ""; + } + if(model instanceof ModelImpl) { + processedModels.add(name); + ModelImpl impl = (ModelImpl) model; + Map values = new HashMap(); + + if(impl != null && impl.getProperties() != null) { + for(String propertyName : impl.getProperties().keySet()) { + Property property = impl.getProperties().get(propertyName); + values.put(propertyName, resolvePropertyToExample(mediaType, property, processedModels)); + } + } + + return values; + } + + return ""; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/XmlExampleGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/XmlExampleGenerator.java new file mode 100644 index 00000000000..99765195d87 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/XmlExampleGenerator.java @@ -0,0 +1,206 @@ +package io.swagger.codegen.examples; + + +import io.swagger.util.Json; +import io.swagger.models.*; +import io.swagger.models.properties.*; + +import java.text.SimpleDateFormat; +import java.util.*; + +import org.codehaus.plexus.util.StringUtils; + +public class XmlExampleGenerator { + public static String NEWLINE = "\n"; + public static String TAG_START = "<"; + public static String CLOSE_TAG = ">"; + public static String TAG_END = " examples; + protected SimpleDateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + protected SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + private static String EMPTY = ""; + + public XmlExampleGenerator(Map examples) { + this.examples = examples; + if(examples == null) + examples = new HashMap(); + } + + public String toXml(Property property) { + return toXml(null, property, 0, Collections.emptySet()); + } + + protected String toXml(Model model, int indent, Collection path) { + if(model instanceof RefModel) { + RefModel ref = (RefModel) model; + Model actualModel = examples.get(ref.getSimpleRef()); + if(actualModel instanceof ModelImpl) + return modelImplToXml((ModelImpl) actualModel, indent, path); + } + else if(model instanceof ModelImpl) { + return modelImplToXml((ModelImpl) model, indent, path); + } + return null; + } + + protected String modelImplToXml(ModelImpl model, int indent, Collection path) { + final String modelName = model.getName(); + if (path.contains(modelName)) { + return EMPTY; + } + final Set selfPath = new HashSet(path); + selfPath.add(modelName); + + StringBuilder sb = new StringBuilder(); + // attributes + Map attributes = new LinkedHashMap(); + Map elements = new LinkedHashMap(); + + String name = modelName; + String namespace; + String prefix; + Boolean wrapped; + + Xml xml = model.getXml(); + if(xml != null) { + if(xml.getName() != null) + name = xml.getName(); + } + for(String pName : model.getProperties().keySet()) { + Property p = model.getProperties().get(pName); + if(p != null && p.getXml() != null && p.getXml().getAttribute() != null && p.getXml().getAttribute()) + attributes.put(pName, p); + else + elements.put(pName, p); + } + sb.append(indent(indent)).append(TAG_START); + sb.append(name); + for(String pName : attributes.keySet()) { + Property p = attributes.get(pName); + sb.append(" ").append(pName).append("=").append(quote(toXml(null, p, 0, selfPath))); + } + sb.append(CLOSE_TAG); + sb.append(NEWLINE); + for(String pName : elements.keySet()) { + Property p = elements.get(pName); + final String asXml = toXml(pName, p, indent + 1, selfPath); + if (StringUtils.isEmpty(asXml)) { + continue; + } + sb.append(asXml); + sb.append(NEWLINE); + } + sb.append(indent(indent)).append(TAG_END).append(name).append(CLOSE_TAG); + + return sb.toString(); + } + + protected String quote(String string) { + return "\"" + string + "\""; + } + + protected String toXml(String name, Property property, int indent, Collection path) { + if(property == null) { + return ""; + } + StringBuilder sb = new StringBuilder(); + + if(property instanceof ArrayProperty) { + ArrayProperty p = (ArrayProperty) property; + Property inner = p.getItems(); + boolean wrapped = false; + if(property.getXml() != null && property.getXml().getWrapped()) + wrapped = true; + if(wrapped) { + String prefix = EMPTY; + if(name != null) { + sb.append(indent(indent)); + sb.append(openTag(name)); + prefix = NEWLINE; + } + final String asXml = toXml(name, inner, indent + 1, path); + if (StringUtils.isNotEmpty(asXml)) { + sb.append(prefix).append(asXml); + } + if(name != null) { + sb.append(NEWLINE); + sb.append(indent(indent)); + sb.append(closeTag(name)); + } + } + else + sb.append(toXml(name, inner, indent, path)); + } + else if(property instanceof RefProperty) { + RefProperty ref = (RefProperty) property; + Model actualModel = examples.get(ref.getSimpleRef()); + sb.append(toXml(actualModel, indent, path)); + } + else { + if(name != null) { + sb.append(indent(indent)); + sb.append(openTag(name)); + } + sb.append(getExample(property)); + if(name != null) + sb.append(closeTag(name)); + } + return sb.toString(); + } + + protected String getExample(Property property) { + if(property instanceof DateTimeProperty) { + if(property.getExample() != null) + return property.getExample(); + else + return dtFormat.format(new Date()); + } + else if(property instanceof StringProperty) { + if(property.getExample() != null) + return property.getExample(); + else + return "string"; + } + else if(property instanceof DateProperty) { + if(property.getExample() != null) + return property.getExample(); + else + return dateFormat.format(new Date()); + } + else if(property instanceof IntegerProperty) { + if(property.getExample() != null) + return property.getExample(); + else + return "0"; + } + else if(property instanceof BooleanProperty) { + if(property.getExample() != null) + return property.getExample(); + else + return "true"; + } + else if(property instanceof LongProperty) { + if(property.getExample() != null) + return property.getExample(); + else + return "123456"; + } + return "not implemented " + property; + } + + protected String openTag(String name) { + return "<" + name + ">"; + } + + protected String closeTag(String name) { + return ""; + } + + protected String indent(int indent) { + StringBuffer sb = new StringBuffer(); + for(int i = 0; i < indent; i++) { + sb.append(" "); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AkkaScalaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AkkaScalaClientCodegen.java new file mode 100644 index 00000000000..9300657dc51 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AkkaScalaClientCodegen.java @@ -0,0 +1,365 @@ +package io.swagger.codegen.languages; + +import com.google.common.base.CaseFormat; +import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Template; +import io.swagger.codegen.*; +import io.swagger.models.auth.SecuritySchemeDefinition; +import io.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( + 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(); + 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( + 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 postProcessOperations(Map objs) { + if (registerNonStandardStatusCodes) { + try { + @SuppressWarnings("unchecked") + Map> opsMap = (Map>) objs.get("operations"); + HashSet unknownCodes = new HashSet(); + 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 fromSecurity(Map schemes) { + final List codegenSecurities = super.fromSecurity(schemes); + if (!removeOAuthSecurities) + return codegenSecurities; + + // Remove OAuth securities + Iterator 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); + } + } + +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AndroidClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AndroidClientCodegen.java new file mode 100644 index 00000000000..b1bc4f0b08b --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AndroidClientCodegen.java @@ -0,0 +1,259 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class AndroidClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "io.swagger.client"; + protected String groupId = "io.swagger"; + protected String artifactId = "swagger-android-client"; + protected String artifactVersion = "1.0.0"; + protected String projectFolder = "src/main"; + protected String sourceFolder = projectFolder + "/java"; + protected Boolean useAndroidMavenGradlePlugin = true; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "android"; + } + + public String getHelp() { + return "Generates an Android client library."; + } + + public AndroidClientCodegen() { + super(); + outputFolder = "generated-code/android"; + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + templateDir = "android-java"; + 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") + ); + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + + cliOptions.add(new CliOption("invokerPackage", "root package to use for the generated code")); + cliOptions.add(new CliOption("groupId", "groupId for use in the generated build.gradle and pom.xml")); + cliOptions.add(new CliOption("artifactId", "artifactId for use in the generated build.gradle and pom.xml")); + cliOptions.add(new CliOption("artifactVersion", "artifact version for use in the generated build.gradle and pom.xml")); + cliOptions.add(new CliOption("sourceFolder", "source folder for generated code")); + cliOptions.add(new CliOption("useAndroidMavenGradlePlugin", "A flag to toggle android-maven gradle plugin. Default is true.")); + } + + @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 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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // 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) { + // 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 toOperationId(String operationId) { + // 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(operationId, true); + } + + @Override + public void processOpts() { + super.processOpts(); + + if(additionalProperties.containsKey("invokerPackage")) { + this.setInvokerPackage((String)additionalProperties.get("invokerPackage")); + } + else{ + //not set, use default to be passed to template + additionalProperties.put("invokerPackage", invokerPackage); + } + + if(additionalProperties.containsKey("groupId")) { + this.setGroupId((String)additionalProperties.get("groupId")); + } + else{ + //not set, use to be passed to template + additionalProperties.put("groupId", groupId); + } + + if(additionalProperties.containsKey("artifactId")) { + this.setArtifactId((String)additionalProperties.get("artifactId")); + } + else{ + //not set, use to be passed to template + additionalProperties.put("artifactId", artifactId); + } + + if(additionalProperties.containsKey("artifactVersion")) { + this.setArtifactVersion((String)additionalProperties.get("artifactVersion")); + } + else{ + //not set, use to be passed to template + additionalProperties.put("artifactVersion", artifactVersion); + } + + if(additionalProperties.containsKey("sourceFolder")) { + this.setSourceFolder((String)additionalProperties.get("sourceFolder")); + } + + if(additionalProperties.containsKey("useAndroidMavenGradlePlugin")) { + this.setUseAndroidMavenGradlePlugin((Boolean)additionalProperties.get("useAndroidMavenGradlePlugin")); + } + else{ + additionalProperties.put("useAndroidMavenGradlePlugin", useAndroidMavenGradlePlugin); + } + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + additionalProperties.put("useAndroidMavenGradlePlugin", useAndroidMavenGradlePlugin); + + supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle")); + supportingFiles.add(new SupportingFile("build.mustache", "", "build.gradle")); + supportingFiles.add(new SupportingFile("manifest.mustache", projectFolder, "AndroidManifest.xml")); + supportingFiles.add(new SupportingFile("apiInvoker.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiInvoker.java")); + supportingFiles.add(new SupportingFile("httpPatch.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "HttpPatch.java")); + supportingFiles.add(new SupportingFile("jsonUtil.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "JsonUtil.java")); + supportingFiles.add(new SupportingFile("apiException.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiException.java")); + } + + public Boolean getUseAndroidMavenGradlePlugin() { + return useAndroidMavenGradlePlugin; + } + + public void setUseAndroidMavenGradlePlugin(Boolean useAndroidMavenGradlePlugin) { + this.useAndroidMavenGradlePlugin = useAndroidMavenGradlePlugin; + } + + 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; + } + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AsyncScalaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AsyncScalaClientCodegen.java new file mode 100644 index 00000000000..aa202060f1e --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AsyncScalaClientCodegen.java @@ -0,0 +1,194 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class AsyncScalaClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "io.swagger.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-async-scala-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/scala"; + protected String clientName = "SwaggerClient"; + protected String authScheme = ""; + protected boolean authPreemptive = false; + protected boolean asyncHttpClient = !authScheme.isEmpty(); + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "async-scala"; + } + + public String getHelp() { + return "Generates an Asynchronous Scala client library."; + } + + public AsyncScalaClientCodegen() { + super(); + outputFolder = "generated-code/async-scala"; + modelTemplateFiles.put("model.mustache", ".scala"); + apiTemplateFiles.put("api.mustache", ".scala"); + templateDir = "asyncscala"; + apiPackage = "io.swagger.client.api"; + modelPackage = "io.swagger.client.model"; + + reservedWords = new HashSet ( + 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("asyncHttpClient", asyncHttpClient); + additionalProperties.put("authScheme", authScheme); + additionalProperties.put("authPreemptive", authPreemptive); + additionalProperties.put("clientName", clientName); + + supportingFiles.add(new SupportingFile("sbt.mustache", "", "build.sbt")); + supportingFiles.add(new SupportingFile("client.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), clientName + ".scala")); + + importMapping.remove("List"); + importMapping.remove("Set"); + importMapping.remove("Map"); + + importMapping.put("DateTime", "org.joda.time.DateTime"); + importMapping.put("ListBuffer", "scala.collections.mutable.ListBuffer"); + + typeMapping = new HashMap(); + typeMapping.put("enum", "NSString"); + typeMapping.put("array", "List"); + typeMapping.put("set", "Set"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("int", "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"); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Int", + "Long", + "Float", + "Object", + "List", + "Map") + ); + instantiationTypes.put("array", "ListBuffer"); + instantiationTypes.put("map", "HashMap"); + } + + @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 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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + 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 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 "new HashMap[String, " + inner + "]() "; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "new ListBuffer[" + inner + "]() "; + } + else + return "null"; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java new file mode 100644 index 00000000000..3a756ab074e --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java @@ -0,0 +1,192 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class CSharpClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "IO.Swagger.Client"; + protected String groupId = "io.swagger"; + protected String artifactId = "swagger-csharp-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/csharp"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "csharp"; + } + + public String getHelp() { + return "Generates a CSharp client library."; + } + + public CSharpClientCodegen() { + super(); + outputFolder = "generated-code/csharp"; + modelTemplateFiles.put("model.mustache", ".cs"); + apiTemplateFiles.put("api.mustache", ".cs"); + templateDir = "csharp"; + apiPackage = "IO.Swagger.Api"; + modelPackage = "IO.Swagger.Model"; + + reservedWords = new HashSet ( + Arrays.asList( + "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "volatile", "while") + ); + + additionalProperties.put("invokerPackage", invokerPackage); + + supportingFiles.add(new SupportingFile("Configuration.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "Configuration.cs")); + supportingFiles.add(new SupportingFile("ApiClient.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiClient.cs")); + supportingFiles.add(new SupportingFile("ApiException.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiException.cs")); + supportingFiles.add(new SupportingFile("Newtonsoft.Json.dll", "bin", "Newtonsoft.Json.dll")); + supportingFiles.add(new SupportingFile("RestSharp.dll", "bin", "RestSharp.dll")); + supportingFiles.add(new SupportingFile("compile.mustache", "", "compile.bat")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "string", + "bool?", + "double?", + "int?", + "long?", + "float?", + "byte[]", + "List", + "Dictionary", + "DateTime?", + "String", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "Object") + ); + instantiationTypes.put("array", "List"); + instantiationTypes.put("map", "Dictionary"); + + typeMapping = new HashMap(); + typeMapping.put("string", "string"); + typeMapping.put("boolean", "bool?"); + typeMapping.put("integer", "int?"); + typeMapping.put("float", "float?"); + typeMapping.put("long", "long?"); + typeMapping.put("double", "double?"); + typeMapping.put("number", "double?"); + typeMapping.put("datetime", "DateTime?"); + typeMapping.put("date", "DateTime?"); + typeMapping.put("file", "string"); // path to file + typeMapping.put("array", "List"); + typeMapping.put("list", "List"); + typeMapping.put("map", "Dictionary"); + typeMapping.put("object", "Object"); + + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return (outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', '/')).replace('.', File.separatorChar); + } + + public String modelFileFolder() { + return (outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', '/')).replace('.', File.separatorChar); + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) + return name; + + // camelize the variable name + // pet_id => PetId + name = camelize(name); + + // 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) { + // 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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType.toLowerCase())) { + type = typeMapping.get(swaggerType.toLowerCase()); + if(languageSpecificPrimitives.contains(type)) + return type; + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toOperationId(String operationId) { + // 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(operationId); + } + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java new file mode 100644 index 00000000000..b8011d3d459 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java @@ -0,0 +1,241 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { + 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/main/java"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "java"; + } + + public String getHelp() { + return "Generates a Java client library."; + } + + public JavaClientCodegen() { + super(); + outputFolder = "generated-code/java"; + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + templateDir = "Java"; + 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") + ); + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + + cliOptions.add(new CliOption("invokerPackage", "root package for generated code")); + cliOptions.add(new CliOption("groupId", "groupId in generated pom.xml")); + cliOptions.add(new CliOption("artifactId", "artifactId in generated pom.xml")); + cliOptions.add(new CliOption("artifactVersion", "artifact version in generated pom.xml")); + cliOptions.add(new CliOption("sourceFolder", "source folder for generated code")); + } + + @Override + public void processOpts() { + super.processOpts(); + + if(additionalProperties.containsKey("invokerPackage")) { + this.setInvokerPackage((String)additionalProperties.get("invokerPackage")); + } + else{ + //not set, use default to be passed to template + additionalProperties.put("invokerPackage", invokerPackage); + } + + if(additionalProperties.containsKey("groupId")) { + this.setGroupId((String)additionalProperties.get("groupId")); + } + else{ + //not set, use to be passed to template + additionalProperties.put("groupId", groupId); + } + + if(additionalProperties.containsKey("artifactId")) { + this.setArtifactId((String)additionalProperties.get("artifactId")); + } + else{ + //not set, use to be passed to template + additionalProperties.put("artifactId", artifactId); + } + + if(additionalProperties.containsKey("artifactVersion")) { + this.setArtifactVersion((String)additionalProperties.get("artifactVersion")); + } + else{ + //not set, use to be passed to template + additionalProperties.put("artifactVersion", artifactVersion); + } + + if(additionalProperties.containsKey("sourceFolder")) { + this.setSourceFolder((String)additionalProperties.get("sourceFolder")); + } + + final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator); + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("ApiClient.mustache", invokerFolder, "ApiClient.java")); + supportingFiles.add(new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java")); + supportingFiles.add(new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java")); + supportingFiles.add(new SupportingFile("JsonUtil.mustache", invokerFolder, "JsonUtil.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/Authentication.mustache", authFolder, "Authentication.java")); + 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")); + } + + + + @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 String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // 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) { + // 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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toOperationId(String operationId) { + // 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(operationId, true); + } + + 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; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JaxRSServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JaxRSServerCodegen.java new file mode 100644 index 00000000000..0720f6517e1 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JaxRSServerCodegen.java @@ -0,0 +1,200 @@ +package io.swagger.codegen.languages; + +import io.swagger.models.Operation; +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class JaxRSServerCodegen extends JavaClientCodegen implements CodegenConfig { + protected String invokerPackage = "io.swagger.api"; + protected String groupId = "io.swagger"; + protected String artifactId = "swagger-jaxrs-server"; + protected String artifactVersion = "1.0.0"; + protected String title = "Swagger Server"; + + public CodegenType getTag() { + return CodegenType.SERVER; + } + + public String getName() { + return "jaxrs"; + } + + public String getHelp() { + return "Generates a Java JAXRS Server application."; + } + + public JaxRSServerCodegen() { + super.processOpts(); + + sourceFolder = "src/gen/java"; + + outputFolder = System.getProperty( "swagger.codegen.jaxrs.genfolder", "generated-code/javaJaxRS" ); + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + apiTemplateFiles.put("apiService.mustache", ".java"); + apiTemplateFiles.put("apiServiceImpl.mustache", ".java"); + apiTemplateFiles.put("apiServiceFactory.mustache", ".java"); + templateDir = "JavaJaxRS"; + apiPackage = System.getProperty( "swagger.codegen.jaxrs.apipackage", "io.swagger.api") ; + modelPackage = System.getProperty( "swagger.codegen.jaxrs.modelpackage", "io.swagger.model" ); + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + additionalProperties.put("title", title); + + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float") + ); + } + + + @Override + public void processOpts() { + super.processOpts(); + + supportingFiles.clear(); + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("ApiException.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiException.java")); + supportingFiles.add(new SupportingFile("ApiOriginFilter.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiOriginFilter.java")); + supportingFiles.add(new SupportingFile("ApiResponseMessage.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiResponseMessage.java")); + supportingFiles.add(new SupportingFile("NotFoundException.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "NotFoundException.java")); + supportingFiles.add(new SupportingFile("web.mustache", + ("src/main/webapp/WEB-INF"), "web.xml")); + + } + + @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 getTypeDeclaration(inner); + } + return super.getTypeDeclaration(p); + } + + @Override + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + String basePath = resourcePath; + if(basePath.startsWith("/")) + basePath = basePath.substring(1); + int pos = basePath.indexOf("/"); + if(pos > 0) + basePath = basePath.substring(0, pos); + + if(basePath == "") + basePath = "default"; + else { + if(co.path.startsWith("/" + basePath)) + co.path = co.path.substring(("/" + basePath).length()); + co.subresourceOperation = !co.path.isEmpty(); + } + List opList = operations.get(basePath); + if(opList == null) { + opList = new ArrayList(); + operations.put(basePath, opList); + } + opList.add(co); + co.baseName = basePath; + } + + public Map postProcessOperations(Map objs) { + Map operations = (Map)objs.get("operations"); + if(operations != null) { + List ops = (List) operations.get("operation"); + for(CodegenOperation operation : ops) { + if(operation.returnType == null) + operation.returnType = "Void"; + else if(operation.returnType.startsWith("List")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("List<".length(), end); + operation.returnContainer = "List"; + } + } + else if(operation.returnType.startsWith("Map")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("Map<".length(), end); + operation.returnContainer = "Map"; + } + } + else if(operation.returnType.startsWith("Set")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("Set<".length(), end); + operation.returnContainer = "Set"; + } + } + } + } + return objs; + } + + @Override + public String apiFilename(String templateName, String tag) { + + String result = super.apiFilename(templateName, tag); + + if( templateName.endsWith( "Impl.mustache")){ + int ix = result.lastIndexOf( '/' ); + result = result.substring( 0, ix ) + "/impl" + result.substring( ix, result.length()-5 ) + "ServiceImpl.java"; + + String output = System.getProperty( "swagger.codegen.jaxrs.impl.source" ); + if( output != null ){ + result = result.replace( apiFileFolder(), implFileFolder(output)); + } + } + else if( templateName.endsWith( "Factory.mustache")){ + int ix = result.lastIndexOf( '/' ); + result = result.substring( 0, ix ) + "/factories" + result.substring( ix, result.length()-5 ) + "ServiceFactory.java"; + + String output = System.getProperty( "swagger.codegen.jaxrs.impl.source" ); + if( output != null ){ + result = result.replace( apiFileFolder(), implFileFolder(output)); + } + } + else if( templateName.endsWith( "Service.mustache")) { + int ix = result.lastIndexOf('.'); + result = result.substring(0, ix) + "Service.java"; + } + + return result; + } + + private String implFileFolder(String output) { + return outputFolder + "/" + output + "/" + apiPackage().replace('.', File.separatorChar); + } + + public boolean shouldOverwrite( String filename ){ + + return !filename.endsWith( "ServiceImpl.java") && !filename.endsWith( "ServiceFactory.java"); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java new file mode 100644 index 00000000000..eb80937bab7 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java @@ -0,0 +1,196 @@ +package io.swagger.codegen.languages; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import io.swagger.codegen.CodegenConfig; +import io.swagger.codegen.CodegenOperation; +import io.swagger.codegen.CodegenParameter; +import io.swagger.codegen.CodegenResponse; +import io.swagger.codegen.CodegenType; +import io.swagger.codegen.DefaultCodegen; +import io.swagger.codegen.SupportingFile; + +public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig { + protected String apiVersion = "1.0.0"; + protected int serverPort = 8080; + protected String projectName = "swagger-server"; + + public String apiPackage() { + return "controllers"; + } + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see io.swagger.codegen.CodegenType + */ + public CodegenType getTag() { + return CodegenType.SERVER; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator + * to select the library with the -l flag. + * + * @return the friendly name for the generator + */ + public String getName() { + return "nodejs"; + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help + * tips, parameters here + * + * @return A string value for the help message + */ + public String getHelp() { + return "Generates a nodejs server library using the swagger-tools project. By default, " + + "it will also generate service classes--which you can disable with the `-Dnoservice` environment variable."; + } + + public NodeJSServerCodegen() { + super(); + + // set the output folder here + outputFolder = "generated-code/nodejs"; + + /** + * Models. You can write model files using the modelTemplateFiles map. + * if you want to create one template for file, you can do so here. + * for multiple files for model, just put another entry in the `modelTemplateFiles` with + * a different extension + */ + modelTemplateFiles.clear(); + + /** + * Api classes. You can write classes for each Api file with the apiTemplateFiles map. + * as with models, add multiple entries with different extensions for multiple files per + * class + */ + apiTemplateFiles.put( + "controller.mustache", // the template to use + ".js"); // the extension for each file to write + + /** + * Template Location. This is the location which templates will be read from. The generator + * will use the resource stream to attempt to read the templates. + */ + templateDir = "nodejs"; + + /** + * Reserved words. Override this with reserved words specific to your language + */ + reservedWords = new HashSet ( + Arrays.asList( + "break", "case", "class", "catch", "const", "continue", "debugger", + "default", "delete", "do", "else", "export", "extends", "finally", + "for", "function", "if", "import", "in", "instanceof", "let", "new", + "return", "super", "switch", "this", "throw", "try", "typeof", "var", + "void", "while", "with", "yield") + ); + + /** + * Additional Properties. These values can be passed to the templates and + * are available in models, apis, and supporting files + */ + additionalProperties.put("apiVersion", apiVersion); + additionalProperties.put("serverPort", serverPort); + + /** + * Supporting Files. You can write single files for the generator with the + * entire object tree available. If the input file has a suffix of `.mustache + * it will be processed by the template engine. Otherwise, it will be copied + */ + // supportingFiles.add(new SupportingFile("controller.mustache", + // "controllers", + // "controller.js") + // ); + supportingFiles.add(new SupportingFile("swagger.mustache", + "api", + "swagger.json") + ); + supportingFiles.add(new SupportingFile("index.mustache", + "", + "index.js") + ); + supportingFiles.add(new SupportingFile("package.mustache", + "", + "package.json") + ); + if(System.getProperty("noservice") == null) { + apiTemplateFiles.put( + "service.mustache", // the template to use + "Service.js"); // the extension for each file to write + } + } + + @Override + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultController"; + return initialCaps(name); + } + + @Override + public String toApiFilename(String name) { + return toApiName(name); + } + /** + * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping + * those terms here. This logic is only called if a variable matches the reseved words + * + * @return the escaped term + */ + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + /** + * Location to write api files. You can use the apiPackage() as defined when the class is + * instantiated + */ + @Override + public String apiFileFolder() { + return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar); + } + + @Override + public Map postProcessOperations(Map objs) { + @SuppressWarnings("unchecked") + Map objectMap = (Map) objs.get("operations"); + @SuppressWarnings("unchecked") + List operations = (List) objectMap.get("operation"); + for(CodegenOperation operation : operations) { + operation.httpMethod = operation.httpMethod.toLowerCase(); + List params = operation.allParams; + if(params != null && params.size() == 0) + operation.allParams = null; + List responses = operation.responses; + if(responses != null) { + for(CodegenResponse resp : responses) { + if("0".equals(resp.code)) + resp.code = "default"; + } + } + if(operation.examples != null && !operation.examples.isEmpty()) { + // Leave application/json* items only + for (Iterator> it = operation.examples.iterator(); it.hasNext();) { + final Map example = it.next(); + final String contentType = example.get("contentType"); + if (contentType == null || !contentType.startsWith("application/json")) { + it.remove(); + } + } + } + } + return objs; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java new file mode 100644 index 00000000000..d8de7597f1c --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java @@ -0,0 +1,347 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig { + protected Set foundationClasses = new HashSet(); + protected String sourceFolder = "client"; + protected String classPrefix = "SWG"; + protected String projectName = "swaggerClient"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "objc"; + } + + public String getHelp() { + return "Generates an Objective-C client library."; + } + + public ObjcClientCodegen() { + super(); + outputFolder = "generated-code" + File.separator + "objc"; + modelTemplateFiles.put("model-header.mustache", ".h"); + modelTemplateFiles.put("model-body.mustache", ".m"); + apiTemplateFiles.put("api-header.mustache", ".h"); + apiTemplateFiles.put("api-body.mustache", ".m"); + templateDir = "objc"; + modelPackage = ""; + + defaultIncludes = new HashSet( + Arrays.asList( + "bool", + "BOOL", + "int", + "NSString", + "NSObject", + "NSArray", + "NSNumber", + "NSDate", + "NSDictionary", + "NSMutableArray", + "NSMutableDictionary") + ); + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "NSNumber", + "NSString", + "NSObject", + "NSDate", + "bool", + "BOOL") + ); + + // ref: http://www.tutorialspoint.com/objective_c/objective_c_basic_syntax.htm + reservedWords = new HashSet( + Arrays.asList( + "auto", "else", "long", "switch", + "break", "enum", "register", "typedef", + "case", "extern", "return", "union", + "char", "float", "short", "unsigned", + "const", "for", "signed", "void", + "continue", "goto", "sizeof", "volatile", + "default", "if", "id", "static", "while", + "do", "int", "struct", "_Packed", + "double", "protocol", "interface", "implementation", + "NSObject", "NSInteger", "NSNumber", "CGFloat", + "property", "nonatomic", "retain", "strong", + "weak", "unsafe_unretained", "readwrite", "readonly" + )); + + typeMapping = new HashMap(); + typeMapping.put("enum", "NSString"); + typeMapping.put("Date", "NSDate"); + typeMapping.put("DateTime", "NSDate"); + typeMapping.put("boolean", "BOOL"); + typeMapping.put("string", "NSString"); + typeMapping.put("integer", "NSNumber"); + typeMapping.put("int", "NSNumber"); + typeMapping.put("float", "NSNumber"); + typeMapping.put("long", "NSNumber"); + typeMapping.put("double", "NSNumber"); + typeMapping.put("array", "NSArray"); + typeMapping.put("map", "NSDictionary"); + typeMapping.put("number", "NSNumber"); + typeMapping.put("List", "NSArray"); + typeMapping.put("object", "NSObject"); + + importMapping = new HashMap (); + + foundationClasses = new HashSet ( + Arrays.asList( + "NSNumber", + "NSObject", + "NSString", + "NSDate", + "NSDictionary") + ); + + instantiationTypes.put("array", "NSMutableArray"); + instantiationTypes.put("map", "NSMutableDictionary"); + + cliOptions.add(new CliOption("classPrefix", "prefix for generated classes")); + cliOptions.add(new CliOption("sourceFolder", "source folder for generated code")); + cliOptions.add(new CliOption("projectName", "name of the Xcode project in generated Podfile")); + } + + @Override + public void processOpts() { + super.processOpts(); + + if(additionalProperties.containsKey("sourceFolder")) { + this.setSourceFolder((String)additionalProperties.get("sourceFolder")); + } + + if(additionalProperties.containsKey("classPrefix")) { + this.setClassPrefix((String)additionalProperties.get("classPrefix")); + } + + if(additionalProperties.containsKey("projectName")) { + this.setProjectName((String)additionalProperties.get("projectName")); + } + else{ + additionalProperties.put("projectName", projectName); + } + + supportingFiles.add(new SupportingFile("SWGObject.h", sourceFolder, "SWGObject.h")); + supportingFiles.add(new SupportingFile("SWGObject.m", sourceFolder, "SWGObject.m")); + supportingFiles.add(new SupportingFile("SWGQueryParamCollection.h", sourceFolder, "SWGQueryParamCollection.h")); + supportingFiles.add(new SupportingFile("SWGQueryParamCollection.m", sourceFolder, "SWGQueryParamCollection.m")); + supportingFiles.add(new SupportingFile("SWGApiClient.h", sourceFolder, "SWGApiClient.h")); + supportingFiles.add(new SupportingFile("SWGApiClient.m", sourceFolder, "SWGApiClient.m")); + supportingFiles.add(new SupportingFile("SWGFile.h", sourceFolder, "SWGFile.h")); + supportingFiles.add(new SupportingFile("SWGFile.m", sourceFolder, "SWGFile.m")); + supportingFiles.add(new SupportingFile("JSONValueTransformer+ISO8601.m", sourceFolder, "JSONValueTransformer+ISO8601.m")); + supportingFiles.add(new SupportingFile("JSONValueTransformer+ISO8601.h", sourceFolder, "JSONValueTransformer+ISO8601.h")); + supportingFiles.add(new SupportingFile("SWGConfiguration-body.mustache", sourceFolder, "SWGConfiguration.m")); + supportingFiles.add(new SupportingFile("SWGConfiguration-header.mustache", sourceFolder, "SWGConfiguration.h")); + supportingFiles.add(new SupportingFile("Podfile.mustache", "", "Podfile")); + } + + @Override + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return instantiationTypes.get("map"); + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return instantiationTypes.get("array"); + } + else + return null; + } + + @Override + public String getTypeDeclaration(String name) { + if(languageSpecificPrimitives.contains(name) && !foundationClasses.contains(name)) + return name; + else + return name + "*"; + } + + @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) && !foundationClasses.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String getTypeDeclaration(Property p) { + if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + String innerType = getSwaggerType(inner); + + // In this codition, type of property p is array of primitive, + // return container type with pointer, e.g. `NSArray*' + if (languageSpecificPrimitives.contains(innerType)) + return getSwaggerType(p) + "*"; + + // In this codition, type of property p is array of model, + // return container type combine inner type with pointer, e.g. `NSArray*' + String innerTypeDeclaration = getTypeDeclaration(inner); + + if (innerTypeDeclaration.endsWith("*")) + innerTypeDeclaration = innerTypeDeclaration.substring(0, innerTypeDeclaration.length() - 1); + + return getSwaggerType(p) + "<" + innerTypeDeclaration + ">*"; + } + else { + String swaggerType = getSwaggerType(p); + + // In this codition, type of p is objective-c primitive type, e.g. `NSSNumber', + // return type of p with pointer, e.g. `NSNumber*' + if (languageSpecificPrimitives.contains(swaggerType) && + foundationClasses.contains(swaggerType)) { + return swaggerType + "*"; + } + // In this codition, type of p is c primitive type, e.g. `bool', + // return type of p, e.g. `bool' + else if (languageSpecificPrimitives.contains(swaggerType)) { + return swaggerType; + } + // In this codition, type of p is objective-c object type, e.g. `SWGPet', + // return type of p with pointer, e.g. `SWGPet*' + else { + return swaggerType + "*"; + } + } + } + + @Override + public String toModelName(String type) { + type = type.replaceAll("[^0-9a-zA-Z_]", "_"); + + // language build-in classes + if(typeMapping.keySet().contains(type) || + foundationClasses.contains(type) || + importMapping.values().contains(type) || + defaultIncludes.contains(type) || + languageSpecificPrimitives.contains(type)) { + return camelize(type); + } + // custom classes + else { + return classPrefix + camelize(type); + } + } + + @Override + public String toModelFilename(String name) { + // should be the same as the model name + return toModelName(name); + } + + @Override + protected void setNonArrayMapProperty(CodegenProperty property, String type) { + super.setNonArrayMapProperty(property, type); + if("NSDictionary".equals(type)) { + property.setter = "initWithDictionary"; + } + else { + property.setter = "initWithValues"; + } + } + + @Override + public String toModelImport(String name) { + if("".equals(modelPackage())) + return name; + else + return modelPackage() + "." + name; + } + + @Override + public String toDefaultValue(Property p) { + return null; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String toApiName(String name) { + return classPrefix + camelize(name) + "Api"; + } + + public String toApiFilename(String name) { + return classPrefix + camelize(name) + "Api"; + } + + @Override + public String toVarName(String name) { + // replace non-word characters to `_` + // e.g. `created-at` to `created_at` + name = name.replaceAll("[^a-zA-Z0-9_]","_"); + + // if it's all upper case, do noting + if (name.matches("^[A-Z_]$")) + return name; + + // camelize (lower first character) the variable name + // e.g. `pet_id` to `petId` + name = camelize(name, true); + + // for reserved word or word starting with number, prepend `_` + 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); + } + + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String toOperationId(String operationId) { + // 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(operationId, true); + } + + public void setSourceFolder(String sourceFolder) { + this.sourceFolder = sourceFolder; + } + + public void setClassPrefix(String classPrefix) { + this.classPrefix = classPrefix; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PerlClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PerlClientCodegen.java new file mode 100644 index 00000000000..8b4bef52ebe --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PerlClientCodegen.java @@ -0,0 +1,200 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.util.Json; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class PerlClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "SwaggerClient"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "perl"; + } + + public String getHelp() { + return "Generates a Perl client library."; + } + + public PerlClientCodegen() { + super(); + modelPackage = File.separatorChar + "Object"; + outputFolder = "generated-code" + File.separatorChar + "perl"; + modelTemplateFiles.put("object.mustache", ".pm"); + apiTemplateFiles.put("api.mustache", ".pm"); + templateDir = "perl"; + + typeMapping.clear(); + languageSpecificPrimitives.clear(); + + reservedWords = new HashSet ( + Arrays.asList( + "else", "lock", "qw", + "__END__", "elsif", "lt", "qx", + "__FILE__", "eq", "m", "s", + "__LINE__", "exp", "ne", "sub", + "__PACKAGE__", "for", "no", "tr", + "and", "foreach", "or", "unless", + "cmp", "ge", "package", "until", + "continue", "gt", "q", "while", + "CORE", "if", "qq", "xor", + "do", "le", "qr", "y" + ) + ); + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("double"); + languageSpecificPrimitives.add("string"); + languageSpecificPrimitives.add("boolean"); + languageSpecificPrimitives.add("DateTime"); + languageSpecificPrimitives.add("ARRAY"); + languageSpecificPrimitives.add("HASH"); + languageSpecificPrimitives.add("object"); + + typeMapping.put("integer", "int"); + typeMapping.put("long", "int"); + typeMapping.put("float", "double"); + typeMapping.put("double", "double"); + typeMapping.put("boolean", "boolean"); + typeMapping.put("string", "string"); + typeMapping.put("date", "DateTime"); + typeMapping.put("dateTime", "DateTime"); + typeMapping.put("password", "string"); + typeMapping.put("array", "ARRAY"); + typeMapping.put("map", "HASH"); + typeMapping.put("object", "object"); + + supportingFiles.add(new SupportingFile("ApiClient.mustache", ("lib/WWW/" + invokerPackage).replace('/', File.separatorChar), "ApiClient.pm")); + supportingFiles.add(new SupportingFile("Configuration.mustache", ("lib/WWW/" + invokerPackage).replace('/', File.separatorChar), "Configuration.pm")); + supportingFiles.add(new SupportingFile("BaseObject.mustache", ("lib/WWW/" + invokerPackage).replace('/', File.separatorChar), "Object/BaseObject.pm")); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return (outputFolder + "/lib/WWW/" + invokerPackage + apiPackage()).replace('/', File.separatorChar); + } + + public String modelFileFolder() { + return (outputFolder + "/lib/WWW/" + invokerPackage + modelPackage()).replace('/', File.separatorChar); + } + + @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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + } + else + type = swaggerType; + if(type == null) + return null; + return type; + } + + public String toDefaultValue(Property p) { + return "null"; + } + + + @Override + public String toVarName(String name) { + // parameter name starting with number won't compile + // need to escape it by appending _ at the beginning + if (name.matches("^[0-9]")) { + name = "_" + name; + } + + // return the name in underscore style + // PhoneNumber => phone_number + return underscore(name); + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toModelName(String name) { + // model name cannot use reserved keyword + if(reservedWords.contains(name)) + escapeReservedWord(name); // e.g. return => _return + + // 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 toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // e.g. phone_number_api.rb => PhoneNumberApi.rb + return camelize(name) + "Api"; + } + + @Override + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultApi"; + // e.g. phone_number_api => PhoneNumberApi + return camelize(name) + "Api"; + } + + @Override + public String toOperationId(String operationId) { + // 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 underscore(operationId); + } + + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PhpClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PhpClientCodegen.java new file mode 100644 index 00000000000..e1bdf1d0d5d --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PhpClientCodegen.java @@ -0,0 +1,184 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.util.Json; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "php"; + } + + public String getHelp() { + return "Generates a PHP client library."; + } + + public PhpClientCodegen() { + super(); + + invokerPackage = camelize("SwaggerClient"); + + String packagePath = invokerPackage + "-php"; + + modelPackage = packagePath + "/lib/models"; + apiPackage = packagePath + "/lib"; + outputFolder = "generated-code/php"; + modelTemplateFiles.put("model.mustache", ".php"); + apiTemplateFiles.put("api.mustache", ".php"); + templateDir = "php"; + + reservedWords = new HashSet ( + Arrays.asList( + "__halt_compiler", "abstract", "and", "array", "as", "break", "callable", "case", "catch", "class", "clone", "const", "continue", "declare", "default", "die", "do", "echo", "else", "elseif", "empty", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "eval", "exit", "extends", "final", "for", "foreach", "function", "global", "goto", "if", "implements", "include", "include_once", "instanceof", "insteadof", "interface", "isset", "list", "namespace", "new", "or", "print", "private", "protected", "public", "require", "require_once", "return", "static", "switch", "throw", "trait", "try", "unset", "use", "var", "while", "xor") + ); + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + // ref: http://php.net/manual/en/language.types.intro.php + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "boolean", + "int", + "integer", + "double", + "float", + "string", + "object", + "DateTime", + "mixed", + "number") + ); + + instantiationTypes.put("array", "array"); + instantiationTypes.put("map", "map"); + + // ref: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#data-types + typeMapping = new HashMap(); + typeMapping.put("integer", "int"); + typeMapping.put("long", "int"); + typeMapping.put("float", "float"); + typeMapping.put("double", "double"); + typeMapping.put("string", "string"); + typeMapping.put("byte", "int"); + typeMapping.put("boolean", "boolean"); + typeMapping.put("date", "DateTime"); + typeMapping.put("datetime", "DateTime"); + typeMapping.put("file", "string"); + typeMapping.put("map", "map"); + typeMapping.put("array", "array"); + typeMapping.put("list", "array"); + typeMapping.put("object", "object"); + + supportingFiles.add(new SupportingFile("composer.mustache", packagePath.replace('/', File.separatorChar), "composer.json")); + supportingFiles.add(new SupportingFile("configuration.mustache", (packagePath + "/lib").replace('/', File.separatorChar), "Configuration.php")); + supportingFiles.add(new SupportingFile("ApiClient.mustache", (packagePath + "/lib").replace('/', File.separatorChar), "ApiClient.php")); + supportingFiles.add(new SupportingFile("ApiException.mustache", (packagePath + "/lib").replace('/', File.separatorChar), "ApiException.php")); + supportingFiles.add(new SupportingFile("require.mustache", packagePath.replace('/', File.separatorChar), invokerPackage + ".php")); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return (outputFolder + "/" + apiPackage()).replace('/', File.separatorChar); + } + + public String modelFileFolder() { + return (outputFolder + "/" + modelPackage()).replace('/', File.separatorChar); + } + + @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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + else if (instantiationTypes.containsKey(type)) { + return type; + } + } + else + type = swaggerType; + if(type == null) + return null; + return toModelName(type); + } + + public String toDefaultValue(Property p) { + return "null"; + } + + + @Override + public String toVarName(String name) { + // parameter name starting with number won't compile + // need to escape it by appending _ at the beginning + if (name.matches("^[0-9]")) { + name = "_" + name; + } + + // return the name in underscore style + // PhoneNumber => phone_number + return underscore(name); + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toModelName(String name) { + // model name cannot use reserved keyword + if(reservedWords.contains(name)) + escapeReservedWord(name); // e.g. return => _return + + // 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); + } + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/Python3ClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/Python3ClientCodegen.java new file mode 100755 index 00000000000..04f3cd6598d --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/Python3ClientCodegen.java @@ -0,0 +1,198 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.io.File; +import java.util.*; + +public class Python3ClientCodegen extends DefaultCodegen implements CodegenConfig { + String module = "client"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "python3"; + } + + public String getHelp() { + return "Generates a Python3 client library."; + } + + public Python3ClientCodegen() { + super(); + outputFolder = "generated-code/python3"; + modelTemplateFiles.put("model.mustache", ".py"); + apiTemplateFiles.put("api.mustache", ".py"); + templateDir = "python3"; + + apiPackage = module; + modelPackage = module + ".models"; + + languageSpecificPrimitives.clear(); + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("float"); + //languageSpecificPrimitives.add("long"); + languageSpecificPrimitives.add("list"); + languageSpecificPrimitives.add("bool"); + languageSpecificPrimitives.add("str"); + languageSpecificPrimitives.add("datetime"); + + typeMapping.clear(); + typeMapping.put("integer", "int"); + typeMapping.put("float", "float"); + typeMapping.put("long", "int"); + typeMapping.put("double", "float"); + typeMapping.put("array", "list"); + typeMapping.put("map", "map"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "str"); + typeMapping.put("date", "datetime"); + + // from https://docs.python.org/release/2.5.4/ref/keywords.html + reservedWords = new HashSet ( + Arrays.asList( + "and", "del", "from", "not", "while", "as", "elif", "global", "or", "with", + "assert", "else", "if", "pass", "yield", "break", "except", "import", + "print", "class", "exec", "in", "raise", "continue", "finally", "is", + "return", "def", "for", "lambda", "try")); + + //supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("swagger.mustache", module, "swagger.py")); + supportingFiles.add(new SupportingFile("__init__.mustache", module, "__init__.py")); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + apiPackage().replace('.', File.separatorChar); + } + + public String modelFileFolder() { + return outputFolder + "/" + modelPackage().replace('.', File.separatorChar); + } + + @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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + } + else + type = swaggerType; + return type; + } + + public String toDefaultValue(Property p) { + // TODO: Support Python def value + return "null"; + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // if it's all uppper case, convert to lower case + if (name.matches("^[A-Z_]*$")) + name = name.toLowerCase(); + + // camelize (lower first character) the variable name + // petId => pet_id + name = underscore(name); + + // 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) { + // 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) { + // 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"); + + // underscore the model file name + // PhoneNumber.rb => phone_number.rb + return underscore(name); + } + + @Override + public String toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // e.g. PhoneNumberApi.rb => phone_number_api.rb + return underscore(name) + "_api"; + } + + @Override + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultApi"; + // e.g. phone_number_api => PhoneNumberApi + return camelize(name) + "Api"; + } + + @Override + public String toApiVarName(String name) { + if(name.length() == 0) + return "default_api"; + return underscore(name) + "_api"; + } + + @Override + public String toOperationId(String operationId) { + // 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 underscore(operationId); + } + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java new file mode 100755 index 00000000000..ba3574d9f67 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java @@ -0,0 +1,215 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.io.File; +import java.util.*; + +public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String module = "SwaggerPetstore"; + protected String invokerPackage; + protected String eggPackage; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "python"; + } + + public String getHelp() { + return "Generates a Python client library."; + } + + public PythonClientCodegen() { + super(); + + eggPackage = module + "-python"; + + invokerPackage = eggPackage + File.separatorChar + module; + + outputFolder = "generated-code" + File.separatorChar + "python"; + modelTemplateFiles.put("model.mustache", ".py"); + apiTemplateFiles.put("api.mustache", ".py"); + templateDir = "python"; + + apiPackage = invokerPackage + File.separatorChar + "apis"; + modelPackage = invokerPackage + File.separatorChar + "models"; + + languageSpecificPrimitives.clear(); + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("float"); + languageSpecificPrimitives.add("list"); + languageSpecificPrimitives.add("bool"); + languageSpecificPrimitives.add("str"); + languageSpecificPrimitives.add("datetime"); + + typeMapping.clear(); + typeMapping.put("integer", "int"); + typeMapping.put("float", "float"); + typeMapping.put("long", "int"); + typeMapping.put("double", "float"); + typeMapping.put("array", "list"); + typeMapping.put("map", "map"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "str"); + typeMapping.put("date", "datetime"); + + // from https://docs.python.org/release/2.5.4/ref/keywords.html + reservedWords = new HashSet ( + Arrays.asList( + "and", "del", "from", "not", "while", "as", "elif", "global", "or", "with", + "assert", "else", "if", "pass", "yield", "break", "except", "import", + "print", "class", "exec", "in", "raise", "continue", "finally", "is", + "return", "def", "for", "lambda", "try")); + + additionalProperties.put("module", module); + + supportingFiles.add(new SupportingFile("README.mustache", eggPackage, "README.md")); + supportingFiles.add(new SupportingFile("setup.mustache", eggPackage, "setup.py")); + supportingFiles.add(new SupportingFile("api_client.mustache", invokerPackage, "api_client.py")); + supportingFiles.add(new SupportingFile("rest.mustache", invokerPackage, "rest.py")); + supportingFiles.add(new SupportingFile("configuration.mustache", invokerPackage, "configuration.py")); + supportingFiles.add(new SupportingFile("__init__package.mustache", invokerPackage, "__init__.py")); + supportingFiles.add(new SupportingFile("__init__model.mustache", modelPackage, "__init__.py")); + supportingFiles.add(new SupportingFile("__init__api.mustache", apiPackage, "__init__.py")); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separatorChar + apiPackage().replace('.', File.separatorChar); + } + + public String modelFileFolder() { + return outputFolder + File.separatorChar + modelPackage().replace('.', File.separatorChar); + } + + @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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + } else { + type = toModelName(swaggerType); + } + return type; + } + + public String toDefaultValue(Property p) { + // TODO: Support Python def value + return "null"; + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // if it's all uppper case, convert to lower case + if (name.matches("^[A-Z_]*$")) + name = name.toLowerCase(); + + // underscore the variable name + // petId => pet_id + name = underscore(dropDots(name)); + + // for reserved word or word starting with number, append _ + if(reservedWords.contains(name) || name.matches("^\\d.*")) + name = escapeReservedWord(name); + + return name; + } + + private static String dropDots(String str) { + return str.replaceAll("\\.", "_"); + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toModelName(String 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) { + // 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"); + + // underscore the model file name + // PhoneNumber => phone_number + return underscore(dropDots(name)); + } + + @Override + public String toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // e.g. PhoneNumberApi.rb => phone_number_api.rb + return underscore(name) + "_api"; + } + + @Override + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultApi"; + // e.g. phone_number_api => PhoneNumberApi + return camelize(name) + "Api"; + } + + @Override + public String toApiVarName(String name) { + if(name.length() == 0) + return "default_api"; + return underscore(name) + "_api"; + } + + @Override + public String toOperationId(String operationId) { + // 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 underscore(operationId); + } + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/Qt5CPPGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/Qt5CPPGenerator.java new file mode 100644 index 00000000000..2b3962fb528 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/Qt5CPPGenerator.java @@ -0,0 +1,308 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.util.Json; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class Qt5CPPGenerator extends DefaultCodegen implements CodegenConfig { + protected Set foundationClasses = new HashSet(); + + // source folder where to write the files + protected String sourceFolder = "client"; + protected String apiVersion = "1.0.0"; + protected final String PREFIX = "SWG"; + protected Map namespaces = new HashMap(); + protected Set systemIncludes = new HashSet(); + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see io.swagger.codegen.CodegenType + */ + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator + * to select the library with the -l flag. + * + * @return the friendly name for the generator + */ + public String getName() { + return "qt5cpp"; + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help + * tips, parameters here + * + * @return A string value for the help message + */ + public String getHelp() { + return "Generates a qt5 C++ client library."; + } + + public Qt5CPPGenerator() { + super(); + + // set the output folder here + outputFolder = "generated-code/qt5cpp"; + + /** + * Models. You can write model files using the modelTemplateFiles map. + * if you want to create one template for file, you can do so here. + * for multiple files for model, just put another entry in the `modelTemplateFiles` with + * a different extension + */ + modelTemplateFiles.put( + "model-header.mustache", + ".h"); + + modelTemplateFiles.put( + "model-body.mustache", + ".cpp"); + + /** + * Api classes. You can write classes for each Api file with the apiTemplateFiles map. + * as with models, add multiple entries with different extensions for multiple files per + * class + */ + apiTemplateFiles.put( + "api-header.mustache", // the template to use + ".h"); // the extension for each file to write + + apiTemplateFiles.put( + "api-body.mustache", // the template to use + ".cpp"); // the extension for each file to write + + /** + * Template Location. This is the location which templates will be read from. The generator + * will use the resource stream to attempt to read the templates. + */ + templateDir = "qt5cpp"; + + /** + * Reserved words. Override this with reserved words specific to your language + */ + reservedWords = new HashSet ( + Arrays.asList( + "sample1", // replace with static values + "sample2") + ); + + /** + * Additional Properties. These values can be passed to the templates and + * are available in models, apis, and supporting files + */ + additionalProperties.put("apiVersion", apiVersion); + additionalProperties().put("prefix", PREFIX); + + /** + * Language Specific Primitives. These types will not trigger imports by + * the client generator + */ + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "bool", + "qint32", + "qint64") + ); + + supportingFiles.add(new SupportingFile("helpers-header.mustache", sourceFolder, PREFIX + "Helpers.h")); + supportingFiles.add(new SupportingFile("helpers-body.mustache", sourceFolder, PREFIX + "Helpers.cpp")); + supportingFiles.add(new SupportingFile("HttpRequest.h", sourceFolder, PREFIX + "HttpRequest.h")); + supportingFiles.add(new SupportingFile("HttpRequest.cpp", sourceFolder, PREFIX + "HttpRequest.cpp")); + supportingFiles.add(new SupportingFile("modelFactory.mustache", sourceFolder, PREFIX + "ModelFactory.h")); + supportingFiles.add(new SupportingFile("object.mustache", sourceFolder, PREFIX + "Object.h")); + + super.typeMapping = new HashMap(); + + typeMapping.put("Date", "QDate"); + typeMapping.put("DateTime", "QDateTime"); + typeMapping.put("string", "QString"); + typeMapping.put("integer", "qint32"); + typeMapping.put("long", "qint64"); + typeMapping.put("boolean", "bool"); + typeMapping.put("array", "QList"); + typeMapping.put("map", "QMap"); + typeMapping.put("file", "SWGHttpRequestInputFileElement"); + typeMapping.put("object", PREFIX + "Object"); + + importMapping = new HashMap(); + + importMapping.put("SWGHttpRequestInputFileElement", "#include \"" + PREFIX + "HttpRequest.h\""); + + namespaces = new HashMap (); + + foundationClasses.add("QString"); + + systemIncludes.add("QString"); + systemIncludes.add("QList"); + } + + @Override + public String toModelImport(String name) { + if(namespaces.containsKey(name)) { + return "using " + namespaces.get(name) + ";"; + } + else if(systemIncludes.contains(name)) { + return "#include <" + name + ">"; + } + return "#include \"" + name + ".h\""; + } + + /** + * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping + * those terms here. This logic is only called if a variable matches the reseved words + * + * @return the escaped term + */ + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + /** + * Location to write model files. You can use the modelPackage() as defined when the class is + * instantiated + */ + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar); + } + + /** + * Location to write api files. You can use the apiPackage() as defined when the class is + * instantiated + */ + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar); + } + + @Override + public String toModelFilename(String name) { + return PREFIX + initialCaps(name); + } + + @Override + public String toApiFilename(String name) { + return PREFIX + initialCaps(name) + "Api"; + } + + /** + * Optional - type declaration. This is a String which is used by the templates to instantiate your + * types. There is typically special handling for different property types + * + * @return a string value used as the `dataType` field for model templates, `returnType` for api templates + */ + @Override + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(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) + "*"; + } + if(foundationClasses.contains(swaggerType)) + return swaggerType + "*"; + else if(languageSpecificPrimitives.contains(swaggerType)) + return toModelName(swaggerType); + else + return swaggerType + "*"; + } + + @Override + public String toDefaultValue(Property p) { + if(p instanceof StringProperty) + return "new QString(\"\")"; + else if (p instanceof BooleanProperty) + return "false"; + else if(p instanceof DateProperty) + return "NULL"; + else if(p instanceof DateTimeProperty) + return "NULL"; + else if (p instanceof DoubleProperty) + return "0.0"; + else if (p instanceof FloatProperty) + return "0.0f"; + else if (p instanceof IntegerProperty) + return "0"; + else if (p instanceof LongProperty) + return "0L"; + else if (p instanceof DecimalProperty) + return "0.0"; + else if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "new QMap()"; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + if(!languageSpecificPrimitives.contains(inner)) { + inner += "*"; + } + return "new QList<" + inner + ">()"; + } + // else + if(p instanceof RefProperty) { + RefProperty rp = (RefProperty) p; + return "new " + toModelName(rp.getSimpleRef()) + "()"; + } + return "NULL"; + } + + + /** + * Optional - swagger type conversion. This is used to map swagger types in a `Property` into + * either language specific types via `typeMapping` or into complex models if there is not a mapping. + * + * @return a string value of the type or complex model for this property + * @see io.swagger.models.properties.Property + */ + @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)) + return toModelName(type); + if(foundationClasses.contains(type)) + return type; + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toModelName(String type) { + if(typeMapping.keySet().contains(type) || + typeMapping.values().contains(type) || + importMapping.values().contains(type) || + defaultIncludes.contains(type) || + languageSpecificPrimitives.contains(type)) { + return type; + } + else { + return PREFIX + Character.toUpperCase(type.charAt(0)) + type.substring(1); + } + } + + @Override + public String toApiName(String type) { + return PREFIX + Character.toUpperCase(type.charAt(0)) + type.substring(1) + "Api"; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RetrofitClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RetrofitClientCodegen.java new file mode 100644 index 00000000000..1b9bf41aa45 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RetrofitClientCodegen.java @@ -0,0 +1,190 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.Operation; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class RetrofitClientCodegen extends DefaultCodegen implements CodegenConfig { + 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/main/java"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "retrofit"; + } + + public String getHelp() { + return "Generates a Retrofit client library."; + } + + public RetrofitClientCodegen() { + super(); + outputFolder = "generated-code/java"; + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + templateDir = "retrofit"; + 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") + ); + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("service.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ServiceGenerator.java")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "Object") + ); + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + } + + @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 String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // 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) { + // 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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toOperationId(String operationId) { + // 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(operationId, true); + } + + public Map postProcessOperations(Map objs) { + 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; + } +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java new file mode 100644 index 00000000000..941b4fa64ad --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java @@ -0,0 +1,220 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.util.Json; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String gemName = "swagger_client"; + protected String moduleName = null; + protected String libFolder = "lib"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "ruby"; + } + + public String getHelp() { + return "Generates a Ruby client library."; + } + + /** + * Generate Ruby module name from the gem name, e.g. use "SwaggerClient" for "swagger_client". + */ + public String generateModuleName() { + return camelize(gemName.replaceAll("[^\\w]+", "_")); + } + + public RubyClientCodegen() { + super(); + moduleName = generateModuleName(); + modelPackage = gemName + "/models"; + apiPackage = gemName + "/api"; + outputFolder = "generated-code" + File.separatorChar + "ruby"; + modelTemplateFiles.put("model.mustache", ".rb"); + apiTemplateFiles.put("api.mustache", ".rb"); + templateDir = "ruby"; + + typeMapping.clear(); + languageSpecificPrimitives.clear(); + + reservedWords = new HashSet ( + Arrays.asList( + "__FILE__", "and", "def", "end", "in", "or", "self", "unless", "__LINE__", + "begin", "defined?", "ensure", "module", "redo", "super", "until", "BEGIN", + "break", "do", "false", "next", "rescue", "then", "when", "END", "case", + "else", "for", "nil", "retry", "true", "while", "alias", "class", "elsif", + "if", "not", "return", "undef", "yield") + ); + + additionalProperties.put("gemName", gemName); + additionalProperties.put("moduleName", moduleName); + + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("array"); + languageSpecificPrimitives.add("map"); + languageSpecificPrimitives.add("string"); + languageSpecificPrimitives.add("DateTime"); + + typeMapping.put("long", "int"); + typeMapping.put("integer", "int"); + typeMapping.put("Array", "array"); + typeMapping.put("String", "string"); + typeMapping.put("List", "array"); + typeMapping.put("map", "map"); + + String baseFolder = "lib" + File.separatorChar + gemName; + String swaggerFolder = baseFolder + File.separatorChar + "swagger"; + String modelFolder = baseFolder + File.separatorChar + "models"; + supportingFiles.add(new SupportingFile("swagger_client.gemspec.mustache", "", gemName + ".gemspec")); + supportingFiles.add(new SupportingFile("swagger_client.mustache", "lib", gemName + ".rb")); + supportingFiles.add(new SupportingFile("monkey.mustache", baseFolder, "monkey.rb")); + supportingFiles.add(new SupportingFile("swagger.mustache", baseFolder, "swagger.rb")); + supportingFiles.add(new SupportingFile("swagger" + File.separatorChar + "request.mustache", swaggerFolder, "request.rb")); + supportingFiles.add(new SupportingFile("swagger" + File.separatorChar + "response.mustache", swaggerFolder, "response.rb")); + supportingFiles.add(new SupportingFile("swagger" + File.separatorChar + "version.mustache", swaggerFolder, "version.rb")); + supportingFiles.add(new SupportingFile("swagger" + File.separatorChar + "configuration.mustache", swaggerFolder, "configuration.rb")); + supportingFiles.add(new SupportingFile("base_object.mustache", modelFolder, "base_object.rb")); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separatorChar + "lib" + File.separatorChar + gemName + File.separatorChar + "api"; + } + + public String modelFileFolder() { + return outputFolder + File.separatorChar + "lib" + File.separatorChar + gemName + File.separatorChar + "models"; + } + + @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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + } + else + type = swaggerType; + if(type == null) + return null; + return type; + } + + public String toDefaultValue(Property p) { + return "null"; + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // if it's all uppper case, convert to lower case + if (name.matches("^[A-Z_]*$")) + name = name.toLowerCase(); + + // camelize (lower first character) the variable name + // petId => pet_id + name = underscore(name); + + // 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) { + // 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) { + // 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"); + + // underscore the model file name + // PhoneNumber.rb => phone_number.rb + return underscore(name); + } + + @Override + public String toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // e.g. PhoneNumberApi.rb => phone_number_api.rb + return underscore(name) + "_api"; + } + + @Override + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultApi"; + // e.g. phone_number_api => PhoneNumberApi + return camelize(name) + "Api"; + } + + @Override + public String toOperationId(String operationId) { + // 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 underscore(operationId); + } + + @Override + public String toModelImport(String name) { + return modelPackage() + "/" + toModelFilename(name); + } + + @Override + public String toApiImport(String name) { + return apiPackage() + "/" + toApiFilename(name); + } + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalaClientCodegen.java new file mode 100644 index 00000000000..2acc7c4cd0a --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalaClientCodegen.java @@ -0,0 +1,203 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class ScalaClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "io.swagger.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-scala-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/scala"; + protected String authScheme = ""; + protected boolean authPreemptive = false; + protected boolean asyncHttpClient = !authScheme.isEmpty(); + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "scala"; + } + + public String getHelp() { + return "Generates a Scala client library."; + } + + public ScalaClientCodegen() { + super(); + outputFolder = "generated-code/scala"; + modelTemplateFiles.put("model.mustache", ".scala"); + apiTemplateFiles.put("api.mustache", ".scala"); + templateDir = "scala"; + apiPackage = "io.swagger.client.api"; + modelPackage = "io.swagger.client.model"; + + reservedWords = new HashSet ( + 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("asyncHttpClient", asyncHttpClient); + additionalProperties.put("authScheme", authScheme); + additionalProperties.put("authPreemptive", authPreemptive); + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("apiInvoker.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiInvoker.scala")); + + importMapping.remove("List"); + importMapping.remove("Set"); + importMapping.remove("Map"); + + importMapping.put("DateTime", "org.joda.time.DateTime"); + importMapping.put("ListBuffer", "scala.collections.mutable.ListBuffer"); + + typeMapping = new HashMap(); + typeMapping.put("enum", "NSString"); + typeMapping.put("array", "List"); + typeMapping.put("set", "Set"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("int", "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"); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Int", + "Long", + "Float", + "Object", + "List", + "Map") + ); + instantiationTypes.put("array", "ListBuffer"); + instantiationTypes.put("map", "HashMap"); + } + + @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 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 getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + 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 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 "new HashMap[String, " + inner + "]() "; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "new ListBuffer[" + inner + "]() "; + } + else + return "null"; + } + + + @Override + public String toOperationId(String operationId) { + // 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(operationId, true); + } + +} diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalatraServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalatraServerCodegen.java new file mode 100644 index 00000000000..df2c7e7f0b5 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ScalatraServerCodegen.java @@ -0,0 +1,178 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; +import io.swagger.util.Json; + +import java.util.*; +import java.io.File; + +public class ScalatraServerCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/scala"; + + public CodegenType getTag() { + return CodegenType.SERVER; + } + + public String getName() { + return "scalatra"; + } + + public String getHelp() { + return "Generates a Scala server application with Scalatra."; + } + + public ScalatraServerCodegen() { + super(); + outputFolder = "generated-code/scalatra"; + modelTemplateFiles.put("model.mustache", ".scala"); + apiTemplateFiles.put("api.mustache", ".scala"); + templateDir = "scalatra"; + apiPackage = "com.wordnik.client.api"; + modelPackage = "com.wordnik.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") + ); + + defaultIncludes = new HashSet( + Arrays.asList("double", + "Int", + "Long", + "Float", + "Double", + "char", + "float", + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "List", + "Set", + "Map") + ); + + typeMapping.put("integer", "Int"); + typeMapping.put("long", "Long"); + + additionalProperties.put("appName", "Swagger Sample"); + additionalProperties.put("appName", "Swagger Sample"); + additionalProperties.put("appDescription", "A sample swagger server"); + additionalProperties.put("infoUrl", "http://developers.helloreverb.com"); + additionalProperties.put("infoEmail", "hello@helloreverb.com"); + additionalProperties.put("licenseInfo", "All rights reserved"); + additionalProperties.put("licenseUrl", "http://apache.org/licenses/LICENSE-2.0.html"); + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("build.sbt", "", "build.sbt")); + supportingFiles.add(new SupportingFile("web.xml", "/src/main/webapp/WEB-INF", "web.xml")); + supportingFiles.add(new SupportingFile("JettyMain.scala", sourceFolder, "JettyMain.scala")); + supportingFiles.add(new SupportingFile("Bootstrap.mustache", sourceFolder, "ScalatraBootstrap.scala")); + supportingFiles.add(new SupportingFile("ServletApp.mustache", sourceFolder, "ServletApp.scala")); + supportingFiles.add(new SupportingFile("project/build.properties", "project", "build.properties")); + supportingFiles.add(new SupportingFile("project/plugins.sbt", "project", "plugins.sbt")); + supportingFiles.add(new SupportingFile("sbt", "", "sbt")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "Object") + ); + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + + importMapping = new HashMap (); + importMapping.put("BigDecimal", "java.math.BigDecimal"); + importMapping.put("UUID", "java.util.UUID"); + importMapping.put("File", "java.io.File"); + importMapping.put("Date", "java.util.Date"); + importMapping.put("Timestamp", "java.sql.Timestamp"); + importMapping.put("Map", "java.util.Map"); + importMapping.put("HashMap", "java.util.HashMap"); + importMapping.put("Array", "java.util.List"); + importMapping.put("ArrayList", "java.util.ArrayList"); + importMapping.put("DateTime", "org.joda.time.DateTime"); + importMapping.put("LocalDateTime", "org.joda.time.LocalDateTime"); + importMapping.put("LocalDate", "org.joda.time.LocalDate"); + importMapping.put("LocalTime", "org.joda.time.LocalTime"); + } + + @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 postProcessOperations(Map objs) { + Map operations = (Map) objs.get("operations"); + List operationList = (List) operations.get("operation"); + for(CodegenOperation op: operationList) { + op.httpMethod = op.httpMethod.toLowerCase(); + } + return 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 String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SpringMVCServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SpringMVCServerCodegen.java new file mode 100644 index 00000000000..4c3a894155b --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SpringMVCServerCodegen.java @@ -0,0 +1,165 @@ +package io.swagger.codegen.languages; + +import io.swagger.models.Operation; +import io.swagger.models.Path; +import io.swagger.util.Json; +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class SpringMVCServerCodegen extends JavaClientCodegen implements CodegenConfig { + protected String invokerPackage = "io.swagger.api"; + protected String groupId = "io.swagger"; + protected String artifactId = "swagger-spring-mvc-server"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/java"; + protected String title = "Petstore Server"; + + protected String configPackage = ""; + + public CodegenType getTag() { + return CodegenType.SERVER; + } + + public String getName() { + return "spring-mvc"; + } + + public String getHelp() { + return "Generates a Java Spring-MVC Server application using the SpringFox integration."; + } + + public SpringMVCServerCodegen() { + super(); + outputFolder = "generated-code/javaSpringMVC"; + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + templateDir = "JavaSpringMVC"; + apiPackage = "io.swagger.api"; + modelPackage = "io.swagger.model"; + configPackage = "io.swagger.configuration"; + + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + additionalProperties.put("title", title); + additionalProperties.put("apiPackage", apiPackage); + additionalProperties.put("configPackage", configPackage); + + supportingFiles.clear(); + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("apiException.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiException.java")); + supportingFiles.add(new SupportingFile("apiOriginFilter.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiOriginFilter.java")); + supportingFiles.add(new SupportingFile("apiResponseMessage.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiResponseMessage.java")); + supportingFiles.add(new SupportingFile("notFoundException.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "NotFoundException.java")); + + supportingFiles.add(new SupportingFile("swaggerConfig.mustache", + (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "SwaggerConfig.java")); + supportingFiles.add(new SupportingFile("webApplication.mustache", + (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "WebApplication.java")); + supportingFiles.add(new SupportingFile("webMvcConfiguration.mustache", + (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "WebMvcConfiguration.java")); + supportingFiles.add(new SupportingFile("swaggerUiConfiguration.mustache", + (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "SwaggerUiConfiguration.java")); + supportingFiles.add(new SupportingFile("swagger.properties", + ("src.main.resources").replace(".", java.io.File.separator), "swagger.properties")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float") + ); + } + + @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 getTypeDeclaration(inner); + } + return super.getTypeDeclaration(p); + } + + @Override + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + String basePath = resourcePath; + if(basePath.startsWith("/")) + basePath = basePath.substring(1); + int pos = basePath.indexOf("/"); + if(pos > 0) + basePath = basePath.substring(0, pos); + + if(basePath == "") + basePath = "default"; + else { + if(co.path.startsWith("/" + basePath)) + co.path = co.path.substring(("/" + basePath).length()); + co.subresourceOperation = !co.path.isEmpty(); + } + List opList = operations.get(basePath); + if(opList == null) { + opList = new ArrayList(); + operations.put(basePath, opList); + } + opList.add(co); + co.baseName = basePath; + } + + public Map postProcessOperations(Map objs) { + Map operations = (Map)objs.get("operations"); + if(operations != null) { + List ops = (List) operations.get("operation"); + for(CodegenOperation operation : ops) { + if(operation.returnType == null) + operation.returnType = "Void"; + else if(operation.returnType.startsWith("List")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("List<".length(), end); + operation.returnContainer = "List"; + } + } + else if(operation.returnType.startsWith("Map")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("Map<".length(), end); + operation.returnContainer = "Map"; + } + } + else if(operation.returnType.startsWith("Set")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("Set<".length(), end); + operation.returnContainer = "Set"; + } + } + } + } + return objs; + } +} + diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticDocCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticDocCodegen.java new file mode 100644 index 00000000000..cb403727337 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticDocCodegen.java @@ -0,0 +1,76 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class StaticDocCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "docs"; + + public CodegenType getTag() { + return CodegenType.DOCUMENTATION; + } + + public String getName() { + return "dynamic-html"; + } + + public String getHelp() { + return "Generates a dynamic HTML site."; + } + + public StaticDocCodegen() { + super(); + outputFolder = "docs"; + modelTemplateFiles.put("model.mustache", ".html"); + apiTemplateFiles.put("operation.mustache", ".html"); + templateDir = "swagger-static"; + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("main.mustache", "", "main.js")); + supportingFiles.add(new SupportingFile("assets/css/bootstrap-responsive.css", + outputFolder + "/assets/css", "bootstrap-responsive.css")); + supportingFiles.add(new SupportingFile("assets/css/bootstrap.css", + outputFolder + "/assets/css", "bootstrap.css")); + supportingFiles.add(new SupportingFile("assets/css/style.css", + outputFolder + "/assets/css", "style.css")); + supportingFiles.add(new SupportingFile("assets/images/logo.png", + outputFolder + "/assets/images", "logo.png")); + supportingFiles.add(new SupportingFile("assets/js/bootstrap.js", + outputFolder + "/assets/js", "bootstrap.js")); + supportingFiles.add(new SupportingFile("assets/js/jquery-1.8.3.min.js", + outputFolder + "/assets/js", "jquery-1.8.3.min.js")); + supportingFiles.add(new SupportingFile("assets/js/main.js", + outputFolder + "/assets/js", "main.js")); + supportingFiles.add(new SupportingFile("index.mustache", + outputFolder, "index.html")); + + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator + "operations"; + } + + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator + "models"; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtmlGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtmlGenerator.java new file mode 100644 index 00000000000..0b6e269a859 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtmlGenerator.java @@ -0,0 +1,97 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.Operation; +import io.swagger.models.properties.*; +import io.swagger.util.Json; + +import java.util.*; +import java.io.File; + +public class StaticHtmlGenerator extends DefaultCodegen implements CodegenConfig { + private static final String ALL_OPERATIONS = ""; + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/scala"; + + public CodegenType getTag() { + return CodegenType.DOCUMENTATION; + } + + public String getName() { + return "html"; + } + + public String getHelp() { + return "Generates a static HTML file."; + } + + public StaticHtmlGenerator() { + super(); + outputFolder = "docs"; + templateDir = "htmlDocs"; + + defaultIncludes = new HashSet(); + + additionalProperties.put("appName", "Swagger Sample"); + additionalProperties.put("appDescription", "A sample swagger server"); + additionalProperties.put("infoUrl", "https://helloreverb.com"); + additionalProperties.put("infoEmail", "hello@helloreverb.com"); + additionalProperties.put("licenseInfo", "All rights reserved"); + additionalProperties.put("licenseUrl", "http://apache.org/licenses/LICENSE-2.0.html"); + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("index.mustache", "", "index.html")); + reservedWords = new HashSet(); + + languageSpecificPrimitives = new HashSet(); + importMapping = new HashMap (); + } + + @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 Map postProcessOperations(Map objs) { + Map operations = (Map) objs.get("operations"); + List operationList = (List) operations.get("operation"); + for(CodegenOperation op: operationList) { + op.httpMethod = op.httpMethod.toLowerCase(); + } + return objs; + } + + @Override + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + List opList = operations.get(ALL_OPERATIONS); + if(opList == null) { + opList = new ArrayList(); + operations.put(ALL_OPERATIONS, opList); + } + for (CodegenOperation addedOperation: opList){ + if (addedOperation.operationId.equals(co.operationId) && addedOperation.path.equals(co.path) && addedOperation.httpMethod.equals(co.httpMethod)) { + addedOperation.tags.addAll(co.tags); + return; + } + } + opList.add(co); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerGenerator.java new file mode 100644 index 00000000000..525d8f6a9a9 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerGenerator.java @@ -0,0 +1,45 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.util.*; +import io.swagger.models.Swagger; + +import org.apache.commons.io.FileUtils; + +import java.io.File; + +public class SwaggerGenerator extends DefaultCodegen implements CodegenConfig { + public CodegenType getTag() { + return CodegenType.DOCUMENTATION; + } + + public String getName() { + return "swagger"; + } + + public String getHelp() { + return "Creates a static swagger.json file."; + } + + public SwaggerGenerator() { + super(); + templateDir = "swagger"; + outputFolder = "generated-code/swagger"; + + supportingFiles.add(new SupportingFile("README.md", "", "README.md")); + } + + @Override + public void processSwagger(Swagger swagger) { + String swaggerString = Json.pretty(swagger); + + try{ + String outputFile = outputFolder + File.separator + "swagger.json"; + FileUtils.writeStringToFile(new File(outputFile), swaggerString); + System.out.println("wrote file to " + outputFile); + } + catch(Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerYamlGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerYamlGenerator.java new file mode 100644 index 00000000000..ad25ee69913 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerYamlGenerator.java @@ -0,0 +1,44 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.util.*; +import io.swagger.models.Swagger; + +import org.apache.commons.io.FileUtils; + +import java.io.File; + +public class SwaggerYamlGenerator extends DefaultCodegen implements CodegenConfig { + public CodegenType getTag() { + return CodegenType.DOCUMENTATION; + } + + public String getName() { + return "swagger-yaml"; + } + + public String getHelp() { + return "Creates a static swagger.yaml file."; + } + + public SwaggerYamlGenerator() { + super(); + templateDir = "swagger"; + outputFolder = "generated-code/swagger"; + + supportingFiles.add(new SupportingFile("README.md", "", "README.md")); + } + + @Override + public void processSwagger(Swagger swagger) { + try{ + String swaggerString = Yaml.mapper().writeValueAsString(swagger); + String outputFile = outputFolder + File.separator + "swagger.yaml"; + FileUtils.writeStringToFile(new File(outputFile), swaggerString); + System.out.println("wrote file to " + outputFile); + } + catch(Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftGenerator.java new file mode 100644 index 00000000000..033781beb36 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftGenerator.java @@ -0,0 +1,250 @@ +package io.swagger.codegen.languages; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; +import io.swagger.codegen.*; +import io.swagger.models.Model; +import io.swagger.models.Operation; +import io.swagger.models.parameters.HeaderParameter; +import io.swagger.models.parameters.Parameter; +import io.swagger.models.properties.*; +import org.apache.commons.lang.StringUtils; + +import javax.annotation.Nullable; +import java.util.*; +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SwiftGenerator extends DefaultCodegen implements CodegenConfig { + private static final Pattern PATH_PARAM_PATTERN = Pattern.compile("\\{[a-zA-Z_]+\\}"); + protected String sourceFolder = "Classes/Swaggers"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "swift"; + } + + public String getHelp() { + return "Generates a swift client library."; + } + + public SwiftGenerator() { + super(); + outputFolder = "generated-code/swift"; + modelTemplateFiles.put("model.mustache", ".swift"); + apiTemplateFiles.put("api.mustache", ".swift"); + templateDir = "swift"; + apiPackage = "/APIs"; + modelPackage = "/Models"; + + // Inject application name + String appName = System.getProperty("appName"); + if (appName == null) { + appName = "SwaggerClient"; + } + additionalProperties.put("projectName", appName); + + // Inject base url override + String basePathOverride = System.getProperty("basePathOverride"); + if (basePathOverride != null) { + additionalProperties.put("basePathOverride", basePathOverride); + } + + sourceFolder = appName + "/" + sourceFolder; + + supportingFiles.add(new SupportingFile("Cartfile.mustache", "", "Cartfile")); + supportingFiles.add(new SupportingFile("APIHelper.mustache", sourceFolder, "APIHelper.swift")); + supportingFiles.add(new SupportingFile("AlamofireImplementations.mustache", sourceFolder, "AlamofireImplementations.swift")); + supportingFiles.add(new SupportingFile("Extensions.mustache", sourceFolder, "Extensions.swift")); + supportingFiles.add(new SupportingFile("Models.mustache", sourceFolder, "Models.swift")); + supportingFiles.add(new SupportingFile("APIs.mustache", sourceFolder, "APIs.swift")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "Int", + "Float", + "Double", + "Bool", + "Void", + "String", + "Character") + ); + defaultIncludes = new HashSet( + Arrays.asList( + "NSDate", + "Array", + "Dictionary", + "Set", + "Any", + "Empty", + "AnyObject") + ); + reservedWords = new HashSet( + Arrays.asList( + "class", "break", "as", "associativity", "deinit", "case", "dynamicType", "convenience", "enum", "continue", + "false", "dynamic", "extension", "default", "is", "didSet", "func", "do", "nil", "final", "import", "else", + "self", "get", "init", "fallthrough", "Self", "infix", "internal", "for", "super", "inout", "let", "if", + "true", "lazy", "operator", "in", "COLUMN", "left", "private", "return", "FILE", "mutating", "protocol", + "switch", "FUNCTION", "none", "public", "where", "LINE", "nonmutating", "static", "while", "optional", + "struct", "override", "subscript", "postfix", "typealias", "precedence", "var", "prefix", "Protocol", + "required", "right", "set", "Type", "unowned", "weak") + ); + + typeMapping = new HashMap(); + typeMapping.put("array", "Array"); + typeMapping.put("List", "Array"); + typeMapping.put("map", "Dictionary"); + typeMapping.put("date", "NSDate"); + typeMapping.put("Date", "NSDate"); + typeMapping.put("DateTime", "NSDate"); + typeMapping.put("boolean", "Bool"); + typeMapping.put("string", "String"); + typeMapping.put("char", "Character"); + typeMapping.put("short", "Int"); + typeMapping.put("int", "Int"); + typeMapping.put("long", "Int"); + typeMapping.put("integer", "Int"); + typeMapping.put("Integer", "Int"); + typeMapping.put("float", "Float"); + typeMapping.put("number", "Double"); + typeMapping.put("double", "Double"); + typeMapping.put("object", "AnyObject"); + typeMapping.put("file", "NSData"); + + importMapping = new HashMap(); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + @Override + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + modelPackage().replace('.', File.separatorChar); + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + apiPackage().replace('.', File.separatorChar); + } + + @Override + public String getTypeDeclaration(Property p) { + if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return "[" + getTypeDeclaration(inner) + "]"; + } else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + return "[String:" + getTypeDeclaration(inner) + "]"; + } + return super.getTypeDeclaration(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)) + return toModelName(type); + } else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toDefaultValue(Property p) { + // nil + return null; + } + + @Override + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "[String:" + inner + "]"; + } else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "[" + inner + "]"; + } + return null; + } + + @Override + public CodegenProperty fromProperty(String name, Property p) { + CodegenProperty codegenProperty = super.fromProperty(name, p); + if (codegenProperty.isEnum) { + List> swiftEnums = new ArrayList>(); + List values = (List) codegenProperty.allowableValues.get("values"); + for (String value : values) { + Map map = new HashMap(); + map.put("enum", StringUtils.capitalize(value)); + map.put("raw", value); + swiftEnums.add(map); + } + codegenProperty.allowableValues.put("values", swiftEnums); + codegenProperty.datatypeWithEnum = + StringUtils.left(codegenProperty.datatypeWithEnum, codegenProperty.datatypeWithEnum.length() - "Enum".length()); + } + return codegenProperty; + } + + @Override + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultAPI"; + return initialCaps(name) + "API"; + } + + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map definitions) { + path = normalizePath(path); + List parameters = operation.getParameters(); + parameters = Lists.newArrayList(Iterators.filter(parameters.iterator(), new Predicate() { + @Override + public boolean apply(@Nullable Parameter parameter) { + return !(parameter instanceof HeaderParameter); + } + })); + operation.setParameters(parameters); + return super.fromOperation(path, httpMethod, operation, definitions); + } + + private static String normalizePath(String path) { + StringBuilder builder = new StringBuilder(); + + int cursor = 0; + Matcher matcher = PATH_PARAM_PATTERN.matcher(path); + boolean found = matcher.find(); + while (found) { + String stringBeforeMatch = path.substring(cursor, matcher.start()); + builder.append(stringBeforeMatch); + + String group = matcher.group().substring(1, matcher.group().length() - 1); + group = camelize(group, true); + builder + .append("{") + .append(group) + .append("}"); + + cursor = matcher.end(); + found = matcher.find(); + } + + String stringAfterMatch = path.substring(cursor); + builder.append(stringAfterMatch); + + return builder.toString(); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/TizenClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/TizenClientCodegen.java new file mode 100644 index 00000000000..460befb6609 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/TizenClientCodegen.java @@ -0,0 +1,258 @@ +package io.swagger.codegen.languages; + +import io.swagger.util.Json; +import io.swagger.codegen.*; +import io.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class TizenClientCodegen extends DefaultCodegen implements CodegenConfig { + protected Set foundationClasses = new HashSet(); + protected String sourceFolder = "client"; + protected static String PREFIX = "Sami"; + protected Map namespaces = new HashMap(); + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "tizen"; + } + + public String getHelp() { + return "Generates a Samsung Tizen C++ client library."; + } + + public TizenClientCodegen() { + super(); + outputFolder = "generated-code/tizen"; + modelTemplateFiles.put("model-header.mustache", ".h"); + modelTemplateFiles.put("model-body.mustache", ".cpp"); + apiTemplateFiles.put("api-header.mustache", ".h"); + apiTemplateFiles.put("api-body.mustache", ".cpp"); + templateDir = "tizen"; + modelPackage = ""; + + defaultIncludes = new HashSet( + Arrays.asList( + "bool", + "int", + "long") + ); + languageSpecificPrimitives = new HashSet(); + + additionalProperties().put("prefix", PREFIX); + + reservedWords = new HashSet( + // VERIFY + Arrays.asList( + "void", "char", "short", "int", "void", "char", "short", "int", + "long", "float", "double", "signed", "unsigned", "id", "const", + "volatile", "in", "out", "inout", "bycopy", "byref", "oneway", + "self", "super" + )); + + super.typeMapping = new HashMap(); + + typeMapping.put("Date", "DateTime"); + typeMapping.put("DateTime", "DateTime"); + typeMapping.put("string", "String"); + typeMapping.put("integer", "Integer"); + typeMapping.put("float", "Float"); + typeMapping.put("long", "Long"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("double", "Double"); + typeMapping.put("array", "IList"); + typeMapping.put("map", "HashMap"); + typeMapping.put("number", "Long"); + typeMapping.put("object", PREFIX + "Object"); + + importMapping = new HashMap(); + + namespaces = new HashMap (); + namespaces.put("DateTime", "Tizen::Base::DateTime"); + namespaces.put("Integer", "Tizen::Base::Integer"); + namespaces.put("Long", "Tizen::Base::Long"); + namespaces.put("Boolean", "Tizen::Base::Boolean"); + namespaces.put("Float", "Tizen::Base::Float"); + namespaces.put("String", "Tizen::Base::String"); + namespaces.put("Double", "Tizen::Base::Double"); + namespaces.put("IList", "Tizen::Base::Collection::IList"); + namespaces.put("HashMap", "Tizen::Base::Collection::HashMap"); + namespaces.put("ArrayList", "Tizen::Base::Collection::ArrayList"); + namespaces.put("JsonNumber", "Tizen::Web::Json"); + namespaces.put("JsonString", "Tizen::Web::Json"); + + foundationClasses = new HashSet ( + Arrays.asList( + "String", + "Integer", + "Float") + ); + supportingFiles.clear(); + supportingFiles.add(new SupportingFile("modelFactory.mustache", sourceFolder, PREFIX + "ModelFactory.h")); + supportingFiles.add(new SupportingFile("helpers-header.mustache", sourceFolder, PREFIX + "Helpers.h")); + supportingFiles.add(new SupportingFile("helpers-body.mustache", sourceFolder, PREFIX + "Helpers.cpp")); + supportingFiles.add(new SupportingFile("apiclient-header.mustache", sourceFolder, PREFIX + "ApiClient.h")); + supportingFiles.add(new SupportingFile("apiclient-body.mustache", sourceFolder, PREFIX + "ApiClient.cpp")); + supportingFiles.add(new SupportingFile("object.mustache", sourceFolder, PREFIX + "Object.h")); + supportingFiles.add(new SupportingFile("error-header.mustache", sourceFolder, PREFIX + "Error.h")); + supportingFiles.add(new SupportingFile("error-body.mustache", sourceFolder, PREFIX + "Error.cpp")); + } + + @Override + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return instantiationTypes.get("map"); + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return instantiationTypes.get("array"); + } + else + return null; + } + + @Override + public String getTypeDeclaration(String name) { + if(languageSpecificPrimitives.contains(name) && !foundationClasses.contains(name)) + return name; + else + return name + "*"; + } + + @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) && !foundationClasses.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(p); + if(languageSpecificPrimitives.contains(swaggerType) && !foundationClasses.contains(swaggerType)) + return toModelName(swaggerType); + else + return swaggerType + "*"; + } + + @Override + public String toModelName(String type) { + if(typeMapping.keySet().contains(type) || + typeMapping.values().contains(type) || + foundationClasses.contains(type) || + importMapping.values().contains(type) || + defaultIncludes.contains(type) || + languageSpecificPrimitives.contains(type)) { + return type; + } + else { + return PREFIX + Character.toUpperCase(type.charAt(0)) + type.substring(1); + } + } + + @Override + public String toModelImport(String name) { + if(namespaces.containsKey(name)) { + return "using " + namespaces.get(name) + ";"; + } + return "#include \"" + name + ".h\""; + } + + @Override + public String toDefaultValue(Property p) { + if(p instanceof StringProperty) + return "new String()"; + else if (p instanceof BooleanProperty) + return "new Boolean(false)"; + else if(p instanceof DateProperty) + return "new DateTime()"; + else if(p instanceof DateTimeProperty) + return "new DateTime()"; + else if (p instanceof DoubleProperty) + return "new Double()"; + else if (p instanceof FloatProperty) + return "new Float()"; + else if (p instanceof IntegerProperty) + return "new Integer()"; + else if (p instanceof LongProperty) + return "new Long()"; + else if (p instanceof DecimalProperty) + return "new Long()"; + else if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "new HashMap()"; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "new ArrayList()"; + } + // else + if(p instanceof RefProperty) { + RefProperty rp = (RefProperty) p; + return "new " + toModelName(rp.getSimpleRef()) + "()"; + } + return "null"; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String toModelFilename(String name) { + return PREFIX + initialCaps(name); + } + + @Override + public String toApiName(String name) { + return PREFIX + initialCaps(name) + "Api"; + } + + public String toApiFilename(String name) { + return PREFIX + initialCaps(name) + "Api"; + } + + @Override + public String toVarName(String name) { + String paramName = name.replaceAll("[^a-zA-Z0-9_]",""); + paramName = Character.toUpperCase(paramName.charAt(0)) + paramName.substring(1); + return "p" + paramName; + } + + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String toOperationId(String operationId) { + // 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"); + + // add_pet_by_id => addPetById + return camelize(operationId, true); + } + +}