@Override
 public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
   if ("retrofit".equals(getLibrary()) || "retrofit2".equals(getLibrary())) {
     Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
     if (operations != null) {
       List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
       for (CodegenOperation operation : ops) {
         if (operation.hasConsumes == Boolean.TRUE) {
           Map<String, String> firstType = operation.consumes.get(0);
           if (firstType != null) {
             if ("multipart/form-data".equals(firstType.get("mediaType"))) {
               operation.isMultipart = Boolean.TRUE;
             }
           }
         }
         if (operation.returnType == null) {
           operation.returnType = "Void";
         }
         if ("retrofit2".equals(getLibrary())
             && StringUtils.isNotEmpty(operation.path)
             && operation.path.startsWith("/")) operation.path = operation.path.substring(1);
       }
     }
   }
   return objs;
 }
 @Override
 public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
   // Remove imports of List, ArrayList, Map and HashMap as they are
   // imported in the template already.
   List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
   Pattern pattern = Pattern.compile("java\\.util\\.(List|ArrayList|Map|HashMap)");
   for (Iterator<Map<String, String>> itr = imports.iterator(); itr.hasNext(); ) {
     String _import = itr.next().get("import");
     if (pattern.matcher(_import).matches()) {
       itr.remove();
     }
   }
   return objs;
 }
  @Override
  public CodegenModel fromModel(String name, Model model, Map<String, Model> allDefinitions) {
    CodegenModel codegenModel = super.fromModel(name, model, allDefinitions);

    if (allDefinitions != null
        && codegenModel != null
        && codegenModel.parentSchema != null
        && codegenModel.hasEnums) {
      final Model parentModel = allDefinitions.get(codegenModel.parentSchema);
      final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
      codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel);
    }

    return codegenModel;
  }
  @Override
  public CodegenModel fromModel(String name, Model model, Map<String, Model> allDefinitions) {
    CodegenModel codegenModel = super.fromModel(name, model, allDefinitions);
    if (codegenModel.description != null) {
      codegenModel.imports.add("ApiModel");
    }
    if (allDefinitions != null
        && codegenModel != null
        && codegenModel.parentSchema != null
        && codegenModel.hasEnums) {
      final Model parentModel = allDefinitions.get(codegenModel.parentSchema);
      final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
      codegenModel = AbstractJavaCodegen.reconcileInlineEnums(codegenModel, parentCodegenModel);
    }

    return codegenModel;
  }
 @Override
 public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
   objs = super.postProcessModelsEnum(objs);
   String lib = getLibrary();
   if (StringUtils.isEmpty(lib) || "feign".equals(lib) || "jersey2".equals(lib)) {
     List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
     List<Object> models = (List<Object>) objs.get("models");
     for (Object _mo : models) {
       Map<String, Object> mo = (Map<String, Object>) _mo;
       CodegenModel cm = (CodegenModel) mo.get("model");
       // for enum model
       if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) {
         cm.imports.add(importMapping.get("JsonValue"));
         Map<String, String> item = new HashMap<String, String>();
         item.put("import", importMapping.get("JsonValue"));
         imports.add(item);
       }
     }
   }
   return objs;
 }
  @Override
  public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
    // Remove imports of List, ArrayList, Map and HashMap as they are
    // imported in the template already.
    List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
    Pattern pattern = Pattern.compile("java\\.util\\.(List|ArrayList|Map|HashMap)");
    for (Iterator<Map<String, String>> itr = imports.iterator(); itr.hasNext(); ) {
      String _import = itr.next().get("import");
      if (pattern.matcher(_import).matches()) {
        itr.remove();
      }
    }

    if (usesAnyRetrofitLibrary()) {
      Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
      if (operations != null) {
        List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
        for (CodegenOperation operation : ops) {
          if (operation.hasConsumes == Boolean.TRUE) {
            Map<String, String> firstType = operation.consumes.get(0);
            if (firstType != null) {
              if ("multipart/form-data".equals(firstType.get("mediaType"))) {
                operation.isMultipart = Boolean.TRUE;
              }
            }
          }
          if (operation.returnType == null) {
            operation.returnType = "Void";
          }
          if (usesRetrofit2Library()
              && StringUtils.isNotEmpty(operation.path)
              && operation.path.startsWith("/")) operation.path = operation.path.substring(1);
        }
      }
    }
    return objs;
  }
  public AbstractJavaCodegen() {
    super();
    modelTemplateFiles.put("model.mustache", ".java");
    apiTemplateFiles.put("api.mustache", ".java");
    apiTestTemplateFiles.put("api_test.mustache", ".java");
    modelDocTemplateFiles.put("model_doc.mustache", ".md");
    apiDocTemplateFiles.put("api_doc.mustache", ".md");

    setReservedWordsLowerCase(
        Arrays.asList(
            // used as internal variables, can collide with parameter names
            "localVarPath",
            "localVarQueryParams",
            "localVarHeaderParams",
            "localVarFormParams",
            "localVarPostBody",
            "localVarAccepts",
            "localVarAccept",
            "localVarContentTypes",
            "localVarContentType",
            "localVarAuthNames",
            "localReturnType",
            "ApiClient",
            "ApiException",
            "ApiResponse",
            "Configuration",
            "StringUtil",

            // language reserved words
            "abstract",
            "continue",
            "for",
            "new",
            "switch",
            "assert",
            "default",
            "if",
            "package",
            "synchronized",
            "boolean",
            "do",
            "goto",
            "private",
            "this",
            "break",
            "double",
            "implements",
            "protected",
            "throw",
            "byte",
            "else",
            "import",
            "public",
            "throws",
            "case",
            "enum",
            "instanceof",
            "return",
            "transient",
            "catch",
            "extends",
            "int",
            "short",
            "try",
            "char",
            "final",
            "interface",
            "static",
            "void",
            "class",
            "finally",
            "long",
            "strictfp",
            "volatile",
            "const",
            "float",
            "native",
            "super",
            "while"));

    languageSpecificPrimitives =
        new HashSet<String>(
            Arrays.asList(
                "String", "boolean", "Boolean", "Double", "Integer", "Long", "Float", "Object",
                "byte[]"));
    instantiationTypes.put("array", "ArrayList");
    instantiationTypes.put("map", "HashMap");
    typeMapping.put("date", "Date");
    typeMapping.put("file", "File");
    typeMapping.put("UUID", "String");

    cliOptions.add(
        new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC));
    cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC));
    cliOptions.add(
        new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC));
    cliOptions.add(new CliOption(CodegenConstants.GROUP_ID, CodegenConstants.GROUP_ID_DESC));
    cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_ID, CodegenConstants.ARTIFACT_ID_DESC));
    cliOptions.add(
        new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC));
    cliOptions.add(
        new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC));
    cliOptions.add(
        new CliOption(
            CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC));
    cliOptions.add(
        CliOption.newBoolean(
            CodegenConstants.SERIALIZABLE_MODEL, CodegenConstants.SERIALIZABLE_MODEL_DESC));
    cliOptions.add(
        CliOption.newBoolean(
            CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING,
            CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING_DESC));
    cliOptions.add(
        CliOption.newBoolean(
            FULL_JAVA_UTIL,
            "whether to use fully qualified name for classes under java.util. This option only works for Java API client"));
    cliOptions.add(
        new CliOption("hideGenerationTimestamp", "hides the timestamp when files were generated"));

    CliOption dateLibrary = new CliOption(DATE_LIBRARY, "Option. Date library to use");
    Map<String, String> dateOptions = new HashMap<String, String>();
    dateOptions.put("java8", "Java 8 native");
    dateOptions.put("java8-localdatetime", "Java 8 using LocalDateTime (for legacy app only)");
    dateOptions.put("joda", "Joda");
    dateOptions.put("legacy", "Legacy java.util.Date");
    dateLibrary.setEnum(dateOptions);

    cliOptions.add(dateLibrary);
  }
  public JavaClientCodegen() {
    super();
    outputFolder = "generated-code" + File.separator + "java";
    modelTemplateFiles.put("model.mustache", ".java");
    apiTemplateFiles.put("api.mustache", ".java");
    embeddedTemplateDir = templateDir = "Java";
    apiPackage = "io.swagger.client.api";
    modelPackage = "io.swagger.client.model";

    setReservedWordsLowerCase(
        Arrays.asList(
            // used as internal variables, can collide with parameter names
            "localVarPath",
            "localVarQueryParams",
            "localVarHeaderParams",
            "localVarFormParams",
            "localVarPostBody",
            "localVarAccepts",
            "localVarAccept",
            "localVarContentTypes",
            "localVarContentType",
            "localVarAuthNames",
            "localReturnType",
            "ApiClient",
            "ApiException",
            "ApiResponse",
            "Configuration",
            "StringUtil",

            // language reserved words
            "abstract",
            "continue",
            "for",
            "new",
            "switch",
            "assert",
            "default",
            "if",
            "package",
            "synchronized",
            "boolean",
            "do",
            "goto",
            "private",
            "this",
            "break",
            "double",
            "implements",
            "protected",
            "throw",
            "byte",
            "else",
            "import",
            "public",
            "throws",
            "case",
            "enum",
            "instanceof",
            "return",
            "transient",
            "catch",
            "extends",
            "int",
            "short",
            "try",
            "char",
            "final",
            "interface",
            "static",
            "void",
            "class",
            "finally",
            "long",
            "strictfp",
            "volatile",
            "const",
            "float",
            "native",
            "super",
            "while"));

    languageSpecificPrimitives =
        new HashSet<String>(
            Arrays.asList(
                "String", "boolean", "Boolean", "Double", "Integer", "Long", "Float", "Object",
                "byte[]"));
    instantiationTypes.put("array", "ArrayList");
    instantiationTypes.put("map", "HashMap");
    typeMapping.put("date", "Date");
    typeMapping.put("file", "File");
    typeMapping.put("UUID", "String");

    cliOptions.add(
        new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC));
    cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC));
    cliOptions.add(
        new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC));
    cliOptions.add(new CliOption(CodegenConstants.GROUP_ID, CodegenConstants.GROUP_ID_DESC));
    cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_ID, CodegenConstants.ARTIFACT_ID_DESC));
    cliOptions.add(
        new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC));
    cliOptions.add(
        new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC));
    cliOptions.add(
        new CliOption(
            CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC));
    cliOptions.add(
        CliOption.newBoolean(
            CodegenConstants.SERIALIZABLE_MODEL, CodegenConstants.SERIALIZABLE_MODEL_DESC));
    cliOptions.add(
        CliOption.newBoolean(
            CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING,
            CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING_DESC));
    cliOptions.add(
        CliOption.newBoolean(
            FULL_JAVA_UTIL, "whether to use fully qualified name for classes under java.util"));
    cliOptions.add(
        CliOption.newBoolean(
            USE_RX_JAVA, "Whether to use the RxJava adapter with the retrofit2 library."));
    cliOptions.add(
        new CliOption("hideGenerationTimestamp", "hides the timestamp when files were generated"));

    supportedLibraries.put(
        DEFAULT_LIBRARY, "HTTP client: Jersey client 1.18. JSON processing: Jackson 2.4.2");
    supportedLibraries.put("feign", "HTTP client: Netflix Feign 8.1.1");
    supportedLibraries.put("jersey2", "HTTP client: Jersey client 2.6");
    supportedLibraries.put("okhttp-gson", "HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1");
    supportedLibraries.put(
        RETROFIT_1, "HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1 (Retrofit 1.9.0)");
    supportedLibraries.put(
        RETROFIT_2,
        "HTTP client: OkHttp 2.5.0. JSON processing: Gson 2.4 (Retrofit 2.0.1). Enable the RxJava adapter using '-DuseRxJava=true'. (RxJava 1.1.2)");

    CliOption library =
        new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use");
    library.setDefault(DEFAULT_LIBRARY);
    library.setEnum(supportedLibraries);
    library.setDefault(DEFAULT_LIBRARY);
    cliOptions.add(library);

    CliOption dateLibrary = new CliOption(DATE_LIBRARY, "Option. Date library to use");
    Map<String, String> dateOptions = new HashMap<String, String>();
    dateOptions.put("java8", "Java 8 native");
    dateOptions.put("joda", "Joda");
    dateLibrary.setEnum(dateOptions);

    cliOptions.add(dateLibrary);
  }
  @Override
  public Map<String, Object> postProcessModels(Map<String, Object> objs) {
    List<Object> models = (List<Object>) objs.get("models");
    for (Object _mo : models) {
      Map<String, Object> mo = (Map<String, Object>) _mo;
      CodegenModel cm = (CodegenModel) mo.get("model");
      for (CodegenProperty var : cm.vars) {
        Map<String, Object> allowableValues = var.allowableValues;

        // handle ArrayProperty
        if (var.items != null) {
          allowableValues = var.items.allowableValues;
        }

        if (allowableValues == null) {
          continue;
        }
        List<String> values = (List<String>) allowableValues.get("values");
        if (values == null) {
          continue;
        }

        // put "enumVars" map into `allowableValues", including `name` and `value`
        List<Map<String, String>> enumVars = new ArrayList<Map<String, String>>();
        String commonPrefix = findCommonPrefixOfVars(values);
        int truncateIdx = commonPrefix.length();
        for (String value : values) {
          Map<String, String> enumVar = new HashMap<String, String>();
          String enumName;
          if (truncateIdx == 0) {
            enumName = value;
          } else {
            enumName = value.substring(truncateIdx);
            if ("".equals(enumName)) {
              enumName = value;
            }
          }
          enumVar.put("name", toEnumVarName(enumName));
          enumVar.put("value", value);
          enumVars.add(enumVar);
        }
        allowableValues.put("enumVars", enumVars);
        // handle default value for enum, e.g. available => StatusEnum.AVAILABLE
        if (var.defaultValue != null) {
          String enumName = null;
          for (Map<String, String> enumVar : enumVars) {
            if (var.defaultValue.equals(enumVar.get("value"))) {
              enumName = enumVar.get("name");
              break;
            }
          }
          if (enumName != null) {
            var.defaultValue = var.datatypeWithEnum + "." + enumName;
          }
        }
      }
    }
    return objs;
  }