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 index 87c8b36aad4..d9cf78037b7 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java @@ -343,7 +343,7 @@ public class DefaultCodegen { } /** - * Return the capitalized file name of the model test + * Return the capitalized file name of the model * * @param name the model name * @return the file name of the model diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java index 577f7de8412..7320c9320cf 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java @@ -24,265 +24,310 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class SwiftCodegen extends DefaultCodegen implements CodegenConfig { - public static final String PROJECT_NAME = "projectName"; - public static final String RESPONSE_AS = "responseAs"; - public static final String UNWRAP_REQUIRED = "unwrapRequired"; - public static final String POD_SOURCE = "podSource"; - public static final String POD_AUTHORS = "podAuthors"; - public static final String POD_SOCIAL_MEDIA_URL = "podSocialMediaURL"; - public static final String POD_DOCSET_URL = "podDocsetURL"; - public static final String POD_LICENSE = "podLicense"; - public static final String POD_HOMEPAGE = "podHomepage"; - public static final String POD_SUMMARY = "podSummary"; - public static final String POD_DESCRIPTION = "podDescription"; - public static final String POD_SCREENSHOTS = "podScreenshots"; - public static final String POD_DOCUMENTATION_URL = "podDocumentationURL"; - public static final String SWIFT_USE_API_NAMESPACE = "swiftUseApiNamespace"; - protected static final String LIBRARY_PROMISE_KIT = "PromiseKit"; - protected static final String[] RESPONSE_LIBRARIES = { LIBRARY_PROMISE_KIT }; - protected String projectName = "SwaggerClient"; - protected boolean unwrapRequired; - protected boolean swiftUseApiNamespace; - protected String[] responseAs = new String[0]; - protected String sourceFolder = "Classes" + File.separator + "Swaggers"; - private static final Pattern PATH_PARAM_PATTERN = Pattern.compile("\\{[a-zA-Z_]+\\}"); + public static final String PROJECT_NAME = "projectName"; + public static final String RESPONSE_AS = "responseAs"; + public static final String UNWRAP_REQUIRED = "unwrapRequired"; + public static final String POD_SOURCE = "podSource"; + public static final String POD_AUTHORS = "podAuthors"; + public static final String POD_SOCIAL_MEDIA_URL = "podSocialMediaURL"; + public static final String POD_DOCSET_URL = "podDocsetURL"; + public static final String POD_LICENSE = "podLicense"; + public static final String POD_HOMEPAGE = "podHomepage"; + public static final String POD_SUMMARY = "podSummary"; + public static final String POD_DESCRIPTION = "podDescription"; + public static final String POD_SCREENSHOTS = "podScreenshots"; + public static final String POD_DOCUMENTATION_URL = "podDocumentationURL"; + public static final String SWIFT_USE_API_NAMESPACE = "swiftUseApiNamespace"; + protected static final String LIBRARY_PROMISE_KIT = "PromiseKit"; + protected static final String[] RESPONSE_LIBRARIES = { LIBRARY_PROMISE_KIT }; + protected String projectName = "SwaggerClient"; + protected boolean unwrapRequired; + protected boolean swiftUseApiNamespace; + protected String[] responseAs = new String[0]; + protected String sourceFolder = "Classes" + File.separator + "Swaggers"; + private static final Pattern PATH_PARAM_PATTERN = Pattern.compile("\\{[a-zA-Z_]+\\}"); - @Override - public CodegenType getTag() { - return CodegenType.CLIENT; - } - - @Override - public String getName() { - return "swift"; - } - - @Override - public String getHelp() { - return "Generates a swift client library."; - } - - public SwiftCodegen() { - super(); - outputFolder = "generated-code" + File.separator + "swift"; - modelTemplateFiles.put("model.mustache", ".swift"); - apiTemplateFiles.put("api.mustache", ".swift"); - embeddedTemplateDir = templateDir = "swift"; - apiPackage = File.separator + "APIs"; - modelPackage = File.separator + "Models"; - - languageSpecificPrimitives = new HashSet( - Arrays.asList( - "Int", - "Float", - "Double", - "Bool", - "Void", - "String", - "Character", - "AnyObject") - ); - defaultIncludes = new HashSet( - Arrays.asList( - "NSDate", - "Array", - "Dictionary", - "Set", - "Any", - "Empty", - "AnyObject") - ); - setReservedWordsLowerCase( - 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", "NSURL"); - //TODO binary should be mapped to byte array - // mapped to String as a workaround - typeMapping.put("binary", "String"); - - importMapping = new HashMap(); - - cliOptions.add(new CliOption(PROJECT_NAME, "Project name in Xcode")); - cliOptions.add(new CliOption(RESPONSE_AS, "Optionally use libraries to manage response. Currently " + - StringUtils.join(RESPONSE_LIBRARIES, ", ") + " are available.")); - cliOptions.add(new CliOption(UNWRAP_REQUIRED, "Treat 'required' properties in response as non-optional " + - "(which would crash the app if api returns null as opposed to required option specified in json schema")); - cliOptions.add(new CliOption(POD_SOURCE, "Source information used for Podspec")); - cliOptions.add(new CliOption(CodegenConstants.POD_VERSION, "Version used for Podspec")); - cliOptions.add(new CliOption(POD_AUTHORS, "Authors used for Podspec")); - cliOptions.add(new CliOption(POD_SOCIAL_MEDIA_URL, "Social Media URL used for Podspec")); - cliOptions.add(new CliOption(POD_DOCSET_URL, "Docset URL used for Podspec")); - cliOptions.add(new CliOption(POD_LICENSE, "License used for Podspec")); - cliOptions.add(new CliOption(POD_HOMEPAGE, "Homepage used for Podspec")); - cliOptions.add(new CliOption(POD_SUMMARY, "Summary used for Podspec")); - cliOptions.add(new CliOption(POD_DESCRIPTION, "Description used for Podspec")); - cliOptions.add(new CliOption(POD_SCREENSHOTS, "Screenshots used for Podspec")); - cliOptions.add(new CliOption(POD_DOCUMENTATION_URL, "Documentation URL used for Podspec")); - cliOptions.add(new CliOption(SWIFT_USE_API_NAMESPACE, "Flag to make all the API classes inner-class of {{projectName}}API")); - } - - @Override - public void processOpts() { - super.processOpts(); - - // Setup project name - if (additionalProperties.containsKey(PROJECT_NAME)) { - setProjectName((String) additionalProperties.get(PROJECT_NAME)); - } else { - additionalProperties.put(PROJECT_NAME, projectName); - } - sourceFolder = projectName + File.separator + sourceFolder; - - // Setup unwrapRequired option, which makes all the properties with "required" non-optional - if (additionalProperties.containsKey(UNWRAP_REQUIRED)) { - setUnwrapRequired(Boolean.parseBoolean(String.valueOf(additionalProperties.get(UNWRAP_REQUIRED)))); - } - additionalProperties.put(UNWRAP_REQUIRED, unwrapRequired); - - // Setup unwrapRequired option, which makes all the properties with "required" non-optional - if (additionalProperties.containsKey(RESPONSE_AS)) { - Object responseAsObject = additionalProperties.get(RESPONSE_AS); - if (responseAsObject instanceof String) { - setResponseAs(((String)responseAsObject).split(",")); - } else { - setResponseAs((String[]) responseAsObject); - } - } - additionalProperties.put(RESPONSE_AS, responseAs); - if (ArrayUtils.contains(responseAs, LIBRARY_PROMISE_KIT)) { - additionalProperties.put("usePromiseKit", true); + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; } - // Setup swiftUseApiNamespace option, which makes all the API classes inner-class of {{projectName}}API - if (additionalProperties.containsKey(SWIFT_USE_API_NAMESPACE)) { - swiftUseApiNamespace = Boolean.parseBoolean(String.valueOf(additionalProperties.get(SWIFT_USE_API_NAMESPACE))); + @Override + public String getName() { + return "swift"; } - additionalProperties.put(SWIFT_USE_API_NAMESPACE, swiftUseApiNamespace); - supportingFiles.add(new SupportingFile("Podspec.mustache", "", projectName + ".podspec")); - 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")); - } - - @Override - public String escapeReservedWord(String name) { - return "_" + name; // add an underscore to the name - } - - @Override - public String modelFileFolder() { - return outputFolder + File.separator + sourceFolder + modelPackage().replace('.', File.separatorChar); - } - - @Override - public String apiFileFolder() { - return outputFolder + File.separator + 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) + "]"; + @Override + public String getHelp() { + return "Generates a swift client library."; } - 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)) + public SwiftCodegen() { + super(); + outputFolder = "generated-code" + File.separator + "swift"; + modelTemplateFiles.put("model.mustache", ".swift"); + apiTemplateFiles.put("api.mustache", ".swift"); + embeddedTemplateDir = templateDir = "swift"; + apiPackage = File.separator + "APIs"; + modelPackage = File.separator + "Models"; + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "Int", + "Float", + "Double", + "Bool", + "Void", + "String", + "Character", + "AnyObject") + ); + defaultIncludes = new HashSet( + Arrays.asList( + "NSDate", + "NSURL", // for file + "Array", + "Dictionary", + "Set", + "Any", + "Empty", + "AnyObject") + ); + setReservedWordsLowerCase( + 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", "NSURL"); + //TODO binary should be mapped to byte array + // mapped to String as a workaround + typeMapping.put("binary", "String"); + + importMapping = new HashMap(); + + cliOptions.add(new CliOption(PROJECT_NAME, "Project name in Xcode")); + cliOptions.add(new CliOption(RESPONSE_AS, "Optionally use libraries to manage response. Currently " + + StringUtils.join(RESPONSE_LIBRARIES, ", ") + " are available.")); + cliOptions.add(new CliOption(UNWRAP_REQUIRED, "Treat 'required' properties in response as non-optional " + + "(which would crash the app if api returns null as opposed to required option specified in json schema")); + cliOptions.add(new CliOption(POD_SOURCE, "Source information used for Podspec")); + cliOptions.add(new CliOption(CodegenConstants.POD_VERSION, "Version used for Podspec")); + cliOptions.add(new CliOption(POD_AUTHORS, "Authors used for Podspec")); + cliOptions.add(new CliOption(POD_SOCIAL_MEDIA_URL, "Social Media URL used for Podspec")); + cliOptions.add(new CliOption(POD_DOCSET_URL, "Docset URL used for Podspec")); + cliOptions.add(new CliOption(POD_LICENSE, "License used for Podspec")); + cliOptions.add(new CliOption(POD_HOMEPAGE, "Homepage used for Podspec")); + cliOptions.add(new CliOption(POD_SUMMARY, "Summary used for Podspec")); + cliOptions.add(new CliOption(POD_DESCRIPTION, "Description used for Podspec")); + cliOptions.add(new CliOption(POD_SCREENSHOTS, "Screenshots used for Podspec")); + cliOptions.add(new CliOption(POD_DOCUMENTATION_URL, "Documentation URL used for Podspec")); + cliOptions.add(new CliOption(SWIFT_USE_API_NAMESPACE, "Flag to make all the API classes inner-class of {{projectName}}API")); + } + + @Override + public void processOpts() { + super.processOpts(); + + // Setup project name + if (additionalProperties.containsKey(PROJECT_NAME)) { + setProjectName((String) additionalProperties.get(PROJECT_NAME)); + } else { + additionalProperties.put(PROJECT_NAME, projectName); + } + sourceFolder = projectName + File.separator + sourceFolder; + + // Setup unwrapRequired option, which makes all the properties with "required" non-optional + if (additionalProperties.containsKey(UNWRAP_REQUIRED)) { + setUnwrapRequired(Boolean.parseBoolean(String.valueOf(additionalProperties.get(UNWRAP_REQUIRED)))); + } + additionalProperties.put(UNWRAP_REQUIRED, unwrapRequired); + + // Setup unwrapRequired option, which makes all the properties with "required" non-optional + if (additionalProperties.containsKey(RESPONSE_AS)) { + Object responseAsObject = additionalProperties.get(RESPONSE_AS); + if (responseAsObject instanceof String) { + setResponseAs(((String)responseAsObject).split(",")); + } else { + setResponseAs((String[]) responseAsObject); + } + } + additionalProperties.put(RESPONSE_AS, responseAs); + if (ArrayUtils.contains(responseAs, LIBRARY_PROMISE_KIT)) { + additionalProperties.put("usePromiseKit", true); + } + + // Setup swiftUseApiNamespace option, which makes all the API classes inner-class of {{projectName}}API + if (additionalProperties.containsKey(SWIFT_USE_API_NAMESPACE)) { + swiftUseApiNamespace = Boolean.parseBoolean(String.valueOf(additionalProperties.get(SWIFT_USE_API_NAMESPACE))); + } + additionalProperties.put(SWIFT_USE_API_NAMESPACE, swiftUseApiNamespace); + + supportingFiles.add(new SupportingFile("Podspec.mustache", "", projectName + ".podspec")); + 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")); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder + modelPackage().replace('.', File.separatorChar); + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + 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) || defaultIncludes.contains(type)) + return type; + } else + type = swaggerType; 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", toSwiftyEnumName(value)); - map.put("raw", value); - swiftEnums.add(map); - } - codegenProperty.allowableValues.put("values", swiftEnums); - codegenProperty.datatypeWithEnum = - StringUtils.left(codegenProperty.datatypeWithEnum, codegenProperty.datatypeWithEnum.length() - "Enum".length()); - // Ensure that the enum type doesn't match a reserved word or - // the variable name doesn't match the generated enum type or the - // Swift compiler will generate an error - if (isReservedWord(codegenProperty.datatypeWithEnum) || - name.equals(codegenProperty.datatypeWithEnum)) { - codegenProperty.datatypeWithEnum = escapeReservedWord(codegenProperty.datatypeWithEnum); - } + /** + * Output the proper model name (capitalized) + * + * @param name the name of the model + * @return capitalized model name + */ + @Override + public String toModelName(String name) { + name = sanitizeName(name); // FIXME parameter should not be assigned. Also declare it as "final" + + if (!StringUtils.isEmpty(modelNameSuffix)) { // set model suffix + name = name + "_" + modelNameSuffix; + } + + if (!StringUtils.isEmpty(modelNamePrefix)) { // set model prefix + name = modelNamePrefix + "_" + name; + } + + // camelize the model name + // phone_number => PhoneNumber + name = camelize(name); + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + String modelName = "Object" + name; + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + return name; + } + + /** + * Return the capitalized file name of the model + * + * @param name the model name + * @return the file name of the model + */ + @Override + public String toModelFilename(String name) { + // should be the same as the model name + return toModelName(name); + } + + @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", toSwiftyEnumName(value)); + map.put("raw", value); + swiftEnums.add(map); + } + codegenProperty.allowableValues.put("values", swiftEnums); + codegenProperty.datatypeWithEnum = + StringUtils.left(codegenProperty.datatypeWithEnum, codegenProperty.datatypeWithEnum.length() - "Enum".length()); + // Ensure that the enum type doesn't match a reserved word or + // the variable name doesn't match the generated enum type or the + // Swift compiler will generate an error + if (isReservedWord(codegenProperty.datatypeWithEnum) || + name.equals(codegenProperty.datatypeWithEnum)) { + codegenProperty.datatypeWithEnum = escapeReservedWord(codegenProperty.datatypeWithEnum); + } + } + return codegenProperty; } - return codegenProperty; - } @SuppressWarnings("static-method") public String toSwiftyEnumName(String value) { @@ -295,125 +340,129 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig { } - @Override - public String toApiName(String name) { - if(name.length() == 0) - return "DefaultAPI"; - return initialCaps(name) + "API"; - } - - @Override - public String toOperationId(String operationId) { - // throw exception if method name is empty - if (StringUtils.isEmpty(operationId)) { - throw new RuntimeException("Empty method name (operationId) not allowed"); + @Override + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultAPI"; + return initialCaps(name) + "API"; } - // method name cannot use reserved keyword, e.g. return - if (isReservedWord(operationId)) { - throw new RuntimeException(operationId + " (reserved word) cannot be used as method name"); + @Override + public String toOperationId(String operationId) { + operationId = camelize(sanitizeName(operationId), true); + + // throw exception if method name is empty. This should not happen but keep the check just in case + if (StringUtils.isEmpty(operationId)) { + throw new RuntimeException("Empty method name (operationId) not allowed"); + } + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + String newOperationId = camelize(("call_" + operationId), true); + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId); + return newOperationId; + } + + return operationId; } - return camelize(sanitizeName(operationId), true); - } + @Override + public String toVarName(String name) { + // sanitize name + name = sanitizeName(name); - @Override - public String toVarName(String name) { - // sanitize name - name = sanitizeName(name); + // 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, true); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } - // 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, true); + @Override + public String toParamName(String name) { + // sanitize name + name = sanitizeName(name); - // for reserved word or word starting with number, append _ - if (isReservedWord(name) || name.matches("^\\d.*")) { - name = escapeReservedWord(name); - } + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); - return name; - } + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } - @Override - public String toParamName(String name) { - // sanitize name - name = sanitizeName(name); + // camelize(lower) the variable name + // pet_id => petId + name = camelize(name, true); - // replace - with _ e.g. created-at => created_at - name = name.replaceAll("-", "_"); + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } - // if it's all uppper case, do nothing - if (name.matches("^[A-Z_]*$")) { return name; } - // camelize(lower) the variable name - // pet_id => petId - name = camelize(name, true); - - // for reserved word or word starting with number, append _ - if (isReservedWord(name) || name.matches("^\\d.*")) { - name = escapeReservedWord(name); + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map definitions, Swagger swagger) { + path = normalizePath(path); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + 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, swagger); } - return name; - } + private static String normalizePath(String path) { + StringBuilder builder = new StringBuilder(); - @Override - public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map definitions, Swagger swagger) { - path = normalizePath(path); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. - 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, swagger); - } + 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); - private static String normalizePath(String path) { - StringBuilder builder = new StringBuilder(); + String group = matcher.group().substring(1, matcher.group().length() - 1); + group = camelize(group, true); + builder + .append("{") + .append(group) + .append("}"); - 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); + cursor = matcher.end(); + found = matcher.find(); + } - String group = matcher.group().substring(1, matcher.group().length() - 1); - group = camelize(group, true); - builder - .append("{") - .append(group) - .append("}"); + String stringAfterMatch = path.substring(cursor); + builder.append(stringAfterMatch); - cursor = matcher.end(); - found = matcher.find(); + return builder.toString(); } - String stringAfterMatch = path.substring(cursor); - builder.append(stringAfterMatch); + public void setProjectName(String projectName) { + this.projectName = projectName; + } - return builder.toString(); - } + public void setUnwrapRequired(boolean unwrapRequired) { + this.unwrapRequired = unwrapRequired; + } - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public void setUnwrapRequired(boolean unwrapRequired) { - this.unwrapRequired = unwrapRequired; - } - - public void setResponseAs(String[] responseAs) { - this.responseAs = responseAs; - } + public void setResponseAs(String[] responseAs) { + this.responseAs = responseAs; + } } diff --git a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/PetAPI.swift b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/PetAPI.swift index ca260a2b92a..595907df1be 100644 --- a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/PetAPI.swift +++ b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/PetAPI.swift @@ -166,20 +166,20 @@ public class PetAPI: APIBase { - OAuth: - type: oauth2 - name: petstore_auth - - examples: [{contentType=application/json, example=[ { - "photoUrls" : [ "aeiou" ], - "name" : "doggie", + - examples: [{example=[ { + "tags" : [ { + "id" : 123456789, + "name" : "aeiou" + } ], "id" : 123456789, "category" : { - "name" : "aeiou", - "id" : 123456789 + "id" : 123456789, + "name" : "aeiou" }, - "tags" : [ { - "name" : "aeiou", - "id" : 123456789 - } ], - "status" : "aeiou" -} ]}, {contentType=application/xml, example= + "status" : "aeiou", + "name" : "doggie", + "photoUrls" : [ "aeiou" ] +} ], contentType=application/json}, {example= 123456 doggie @@ -188,21 +188,21 @@ public class PetAPI: APIBase { string -}] - - examples: [{contentType=application/json, example=[ { - "photoUrls" : [ "aeiou" ], - "name" : "doggie", +, contentType=application/xml}] + - examples: [{example=[ { + "tags" : [ { + "id" : 123456789, + "name" : "aeiou" + } ], "id" : 123456789, "category" : { - "name" : "aeiou", - "id" : 123456789 + "id" : 123456789, + "name" : "aeiou" }, - "tags" : [ { - "name" : "aeiou", - "id" : 123456789 - } ], - "status" : "aeiou" -} ]}, {contentType=application/xml, example= + "status" : "aeiou", + "name" : "doggie", + "photoUrls" : [ "aeiou" ] +} ], contentType=application/json}, {example= 123456 doggie @@ -211,7 +211,7 @@ public class PetAPI: APIBase { string -}] +, contentType=application/xml}] - parameter status: (query) Status values that need to be considered for query @@ -272,20 +272,20 @@ public class PetAPI: APIBase { - OAuth: - type: oauth2 - name: petstore_auth - - examples: [{contentType=application/json, example=[ { - "photoUrls" : [ "aeiou" ], - "name" : "doggie", + - examples: [{example=[ { + "tags" : [ { + "id" : 123456789, + "name" : "aeiou" + } ], "id" : 123456789, "category" : { - "name" : "aeiou", - "id" : 123456789 + "id" : 123456789, + "name" : "aeiou" }, - "tags" : [ { - "name" : "aeiou", - "id" : 123456789 - } ], - "status" : "aeiou" -} ]}, {contentType=application/xml, example= + "status" : "aeiou", + "name" : "doggie", + "photoUrls" : [ "aeiou" ] +} ], contentType=application/json}, {example= 123456 doggie @@ -294,21 +294,21 @@ public class PetAPI: APIBase { string -}] - - examples: [{contentType=application/json, example=[ { - "photoUrls" : [ "aeiou" ], - "name" : "doggie", +, contentType=application/xml}] + - examples: [{example=[ { + "tags" : [ { + "id" : 123456789, + "name" : "aeiou" + } ], "id" : 123456789, "category" : { - "name" : "aeiou", - "id" : 123456789 + "id" : 123456789, + "name" : "aeiou" }, - "tags" : [ { - "name" : "aeiou", - "id" : 123456789 - } ], - "status" : "aeiou" -} ]}, {contentType=application/xml, example= + "status" : "aeiou", + "name" : "doggie", + "photoUrls" : [ "aeiou" ] +} ], contentType=application/json}, {example= 123456 doggie @@ -317,7 +317,7 @@ public class PetAPI: APIBase { string -}] +, contentType=application/xml}] - parameter tags: (query) Tags to filter by @@ -375,26 +375,26 @@ public class PetAPI: APIBase { - GET /pet/{petId} - Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions - - OAuth: - - type: oauth2 - - name: petstore_auth - API Key: - type: apiKey api_key - name: api_key - - examples: [{contentType=application/json, example={ - "photoUrls" : [ "aeiou" ], - "name" : "doggie", + - OAuth: + - type: oauth2 + - name: petstore_auth + - examples: [{example={ + "tags" : [ { + "id" : 123456789, + "name" : "aeiou" + } ], "id" : 123456789, "category" : { - "name" : "aeiou", - "id" : 123456789 + "id" : 123456789, + "name" : "aeiou" }, - "tags" : [ { - "name" : "aeiou", - "id" : 123456789 - } ], - "status" : "aeiou" -}}, {contentType=application/xml, example= + "status" : "aeiou", + "name" : "doggie", + "photoUrls" : [ "aeiou" ] +}, contentType=application/json}, {example= 123456 doggie @@ -403,21 +403,21 @@ public class PetAPI: APIBase { string -}] - - examples: [{contentType=application/json, example={ - "photoUrls" : [ "aeiou" ], - "name" : "doggie", +, contentType=application/xml}] + - examples: [{example={ + "tags" : [ { + "id" : 123456789, + "name" : "aeiou" + } ], "id" : 123456789, "category" : { - "name" : "aeiou", - "id" : 123456789 + "id" : 123456789, + "name" : "aeiou" }, - "tags" : [ { - "name" : "aeiou", - "id" : 123456789 - } ], - "status" : "aeiou" -}}, {contentType=application/xml, example= + "status" : "aeiou", + "name" : "doggie", + "photoUrls" : [ "aeiou" ] +}, contentType=application/json}, {example= 123456 doggie @@ -426,7 +426,7 @@ public class PetAPI: APIBase { string -}] +, contentType=application/xml}] - parameter petId: (path) ID of pet that needs to be fetched @@ -678,14 +678,14 @@ public class PetAPI: APIBase { - GET /pet/{petId}?testing_byte_array=true - Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions - - OAuth: - - type: oauth2 - - name: petstore_auth - API Key: - type: apiKey api_key - name: api_key - - examples: [{contentType=application/json, example=""}, {contentType=application/xml, example=not implemented io.swagger.models.properties.BinaryProperty@55e6ae9e}] - - examples: [{contentType=application/json, example=""}, {contentType=application/xml, example=not implemented io.swagger.models.properties.BinaryProperty@55e6ae9e}] + - OAuth: + - type: oauth2 + - name: petstore_auth + - examples: [{example="", contentType=application/json}, {example=not implemented io.swagger.models.properties.BinaryProperty@55e6ae9e, contentType=application/xml}] + - examples: [{example="", contentType=application/json}, {example=not implemented io.swagger.models.properties.BinaryProperty@55e6ae9e, contentType=application/xml}] - parameter petId: (path) ID of pet that needs to be fetched diff --git a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/StoreAPI.swift b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/StoreAPI.swift index e8511765a97..f53163915ef 100644 --- a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/StoreAPI.swift @@ -55,36 +55,36 @@ public class StoreAPI: APIBase { - API Key: - type: apiKey x-test_api_client_secret - name: test_api_client_secret - - examples: [{contentType=application/json, example=[ { - "petId" : 123456789, - "quantity" : 123, + - examples: [{example=[ { "id" : 123456789, - "shipDate" : "2000-01-23T04:56:07.000+0000", + "petId" : 123456789, "complete" : true, - "status" : "aeiou" -} ]}, {contentType=application/xml, example= + "status" : "aeiou", + "quantity" : 123, + "shipDate" : "2000-01-23T04:56:07.000+0000" +} ], contentType=application/json}, {example= 123456 123456 0 2000-01-23T04:56:07.000Z string true -}] - - examples: [{contentType=application/json, example=[ { - "petId" : 123456789, - "quantity" : 123, +, contentType=application/xml}] + - examples: [{example=[ { "id" : 123456789, - "shipDate" : "2000-01-23T04:56:07.000+0000", + "petId" : 123456789, "complete" : true, - "status" : "aeiou" -} ]}, {contentType=application/xml, example= + "status" : "aeiou", + "quantity" : 123, + "shipDate" : "2000-01-23T04:56:07.000+0000" +} ], contentType=application/json}, {example= 123456 123456 0 2000-01-23T04:56:07.000Z string true -}] +, contentType=application/xml}] - parameter status: (query) Status value that needs to be considered for query @@ -143,12 +143,12 @@ public class StoreAPI: APIBase { - API Key: - type: apiKey api_key - name: api_key - - examples: [{contentType=application/json, example={ + - examples: [{example={ "key" : 123 -}}, {contentType=application/xml, example=not implemented io.swagger.models.properties.MapProperty@d1e580af}] - - examples: [{contentType=application/json, example={ +}, contentType=application/json}, {example=not implemented io.swagger.models.properties.MapProperty@d1e580af, contentType=application/xml}] + - examples: [{example={ "key" : 123 -}}, {contentType=application/xml, example=not implemented io.swagger.models.properties.MapProperty@d1e580af}] +}, contentType=application/json}, {example=not implemented io.swagger.models.properties.MapProperty@d1e580af, contentType=application/xml}] - returns: RequestBuilder<[String:Int]> */ @@ -208,36 +208,36 @@ public class StoreAPI: APIBase { - API Key: - type: apiKey x-test_api_client_secret - name: test_api_client_secret - - examples: [{contentType=application/json, example={ - "petId" : 123456789, - "quantity" : 123, + - examples: [{example={ "id" : 123456789, - "shipDate" : "2000-01-23T04:56:07.000+0000", + "petId" : 123456789, "complete" : true, - "status" : "aeiou" -}}, {contentType=application/xml, example= + "status" : "aeiou", + "quantity" : 123, + "shipDate" : "2000-01-23T04:56:07.000+0000" +}, contentType=application/json}, {example= 123456 123456 0 2000-01-23T04:56:07.000Z string true -}] - - examples: [{contentType=application/json, example={ - "petId" : 123456789, - "quantity" : 123, +, contentType=application/xml}] + - examples: [{example={ "id" : 123456789, - "shipDate" : "2000-01-23T04:56:07.000+0000", + "petId" : 123456789, "complete" : true, - "status" : "aeiou" -}}, {contentType=application/xml, example= + "status" : "aeiou", + "quantity" : 123, + "shipDate" : "2000-01-23T04:56:07.000+0000" +}, contentType=application/json}, {example= 123456 123456 0 2000-01-23T04:56:07.000Z string true -}] +, contentType=application/xml}] - parameter body: (body) order placed for purchasing the pet @@ -292,42 +292,42 @@ public class StoreAPI: APIBase { - GET /store/order/{orderId} - For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions - - API Key: - - type: apiKey test_api_key_query (QUERY) - - name: test_api_key_query - API Key: - type: apiKey test_api_key_header - name: test_api_key_header - - examples: [{contentType=application/json, example={ - "petId" : 123456789, - "quantity" : 123, + - API Key: + - type: apiKey test_api_key_query (QUERY) + - name: test_api_key_query + - examples: [{example={ "id" : 123456789, - "shipDate" : "2000-01-23T04:56:07.000+0000", + "petId" : 123456789, "complete" : true, - "status" : "aeiou" -}}, {contentType=application/xml, example= + "status" : "aeiou", + "quantity" : 123, + "shipDate" : "2000-01-23T04:56:07.000+0000" +}, contentType=application/json}, {example= 123456 123456 0 2000-01-23T04:56:07.000Z string true -}] - - examples: [{contentType=application/json, example={ - "petId" : 123456789, - "quantity" : 123, +, contentType=application/xml}] + - examples: [{example={ "id" : 123456789, - "shipDate" : "2000-01-23T04:56:07.000+0000", + "petId" : 123456789, "complete" : true, - "status" : "aeiou" -}}, {contentType=application/xml, example= + "status" : "aeiou", + "quantity" : 123, + "shipDate" : "2000-01-23T04:56:07.000+0000" +}, contentType=application/json}, {example= 123456 123456 0 2000-01-23T04:56:07.000Z string true -}] +, contentType=application/xml}] - parameter orderId: (path) ID of pet that needs to be fetched diff --git a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/UserAPI.swift b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/UserAPI.swift index dffc01db15f..7d304039bb0 100644 --- a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/UserAPI.swift +++ b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/APIs/UserAPI.swift @@ -213,8 +213,8 @@ public class UserAPI: APIBase { - GET /user/login - - - examples: [{contentType=application/json, example="aeiou"}, {contentType=application/xml, example=string}] - - examples: [{contentType=application/json, example="aeiou"}, {contentType=application/xml, example=string}] + - examples: [{example="aeiou", contentType=application/json}, {example=string, contentType=application/xml}] + - examples: [{example="aeiou", contentType=application/json}, {example=string, contentType=application/xml}] - parameter username: (query) The user name for login - parameter password: (query) The password for login in clear text @@ -325,7 +325,7 @@ public class UserAPI: APIBase { - GET /user/{username} - - - examples: [{contentType=application/json, example={ + - examples: [{example={ "id" : 1, "username" : "johnp", "firstName" : "John", @@ -334,7 +334,7 @@ public class UserAPI: APIBase { "password" : "-secret-", "phone" : "0123456789", "userStatus" : 0 -}}] +}, contentType=application/json}] - parameter username: (path) The name that needs to be fetched. Use user1 for testing. diff --git a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/Models.swift b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/Models.swift index f9b6c5ade48..04c07fa97ff 100644 --- a/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/Models.swift +++ b/samples/client/petstore/swift/PetstoreClient/Classes/Swaggers/Models.swift @@ -124,24 +124,6 @@ class Decoders { fatalError("formatter failed to parse \(source)") } - // Decoder for [Order] - Decoders.addDecoder(clazz: [Order].self) { (source: AnyObject) -> [Order] in - return Decoders.decode(clazz: [Order].self, source: source) - } - // Decoder for Order - Decoders.addDecoder(clazz: Order.self) { (source: AnyObject) -> Order in - let sourceDictionary = source as! [NSObject:AnyObject] - let instance = Order() - instance.id = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["id"]) - instance.petId = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["petId"]) - instance.quantity = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["quantity"]) - instance.shipDate = Decoders.decodeOptional(clazz: NSDate.self, source: sourceDictionary["shipDate"]) - instance.status = Order.Status(rawValue: (sourceDictionary["status"] as? String) ?? "") - instance.complete = Decoders.decodeOptional(clazz: Bool.self, source: sourceDictionary["complete"]) - return instance - } - - // Decoder for [User] Decoders.addDecoder(clazz: [User].self) { (source: AnyObject) -> [User] in return Decoders.decode(clazz: [User].self, source: source) @@ -176,20 +158,6 @@ class Decoders { } - // Decoder for [Tag] - Decoders.addDecoder(clazz: [Tag].self) { (source: AnyObject) -> [Tag] in - return Decoders.decode(clazz: [Tag].self, source: source) - } - // Decoder for Tag - Decoders.addDecoder(clazz: Tag.self) { (source: AnyObject) -> Tag in - let sourceDictionary = source as! [NSObject:AnyObject] - let instance = Tag() - instance.id = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["id"]) - instance.name = Decoders.decodeOptional(clazz: String.self, source: sourceDictionary["name"]) - return instance - } - - // Decoder for [Pet] Decoders.addDecoder(clazz: [Pet].self) { (source: AnyObject) -> [Pet] in return Decoders.decode(clazz: [Pet].self, source: source) @@ -207,6 +175,38 @@ class Decoders { return instance } + + // Decoder for [Tag] + Decoders.addDecoder(clazz: [Tag].self) { (source: AnyObject) -> [Tag] in + return Decoders.decode(clazz: [Tag].self, source: source) + } + // Decoder for Tag + Decoders.addDecoder(clazz: Tag.self) { (source: AnyObject) -> Tag in + let sourceDictionary = source as! [NSObject:AnyObject] + let instance = Tag() + instance.id = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["id"]) + instance.name = Decoders.decodeOptional(clazz: String.self, source: sourceDictionary["name"]) + return instance + } + + + // Decoder for [Order] + Decoders.addDecoder(clazz: [Order].self) { (source: AnyObject) -> [Order] in + return Decoders.decode(clazz: [Order].self, source: source) + } + // Decoder for Order + Decoders.addDecoder(clazz: Order.self) { (source: AnyObject) -> Order in + let sourceDictionary = source as! [NSObject:AnyObject] + let instance = Order() + instance.id = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["id"]) + instance.petId = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["petId"]) + instance.quantity = Decoders.decodeOptional(clazz: Int.self, source: sourceDictionary["quantity"]) + instance.shipDate = Decoders.decodeOptional(clazz: NSDate.self, source: sourceDictionary["shipDate"]) + instance.status = Order.Status(rawValue: (sourceDictionary["status"] as? String) ?? "") + instance.complete = Decoders.decodeOptional(clazz: Bool.self, source: sourceDictionary["complete"]) + return instance + } + } } }