@Override
  public void processOpts() {
    super.processOpts();

    if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
      this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
    } else {
      // not set, use default to be passed to template
      additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
    }

    if (additionalProperties.containsKey(CodegenConstants.GROUP_ID)) {
      this.setGroupId((String) additionalProperties.get(CodegenConstants.GROUP_ID));
    } else {
      // not set, use to be passed to template
      additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
    }

    if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_ID)) {
      this.setArtifactId((String) additionalProperties.get(CodegenConstants.ARTIFACT_ID));
    } else {
      // not set, use to be passed to template
      additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
    }

    if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_VERSION)) {
      this.setArtifactVersion((String) additionalProperties.get(CodegenConstants.ARTIFACT_VERSION));
    } else {
      // not set, use to be passed to template
      additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
    }

    if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
      this.setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER));
    }

    if (additionalProperties.containsKey(CodegenConstants.LOCAL_VARIABLE_PREFIX)) {
      this.setLocalVariablePrefix(
          (String) additionalProperties.get(CodegenConstants.LOCAL_VARIABLE_PREFIX));
    }

    if (additionalProperties.containsKey(CodegenConstants.SERIALIZABLE_MODEL)) {
      this.setSerializableModel(
          Boolean.valueOf(
              additionalProperties.get(CodegenConstants.SERIALIZABLE_MODEL).toString()));
    }

    if (additionalProperties.containsKey(CodegenConstants.LIBRARY)) {
      this.setLibrary((String) additionalProperties.get(CodegenConstants.LIBRARY));
    }

    if (additionalProperties.containsKey(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING)) {
      this.setSerializeBigDecimalAsString(
          Boolean.valueOf(
              additionalProperties
                  .get(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING)
                  .toString()));
    }

    // need to put back serializableModel (boolean) into additionalProperties as value in
    // additionalProperties is string
    additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, serializableModel);

    if (additionalProperties.containsKey(FULL_JAVA_UTIL)) {
      this.setFullJavaUtil(Boolean.valueOf(additionalProperties.get(FULL_JAVA_UTIL).toString()));
    }

    if (fullJavaUtil) {
      javaUtilPrefix = "java.util.";
    }
    additionalProperties.put(FULL_JAVA_UTIL, fullJavaUtil);
    additionalProperties.put("javaUtilPrefix", javaUtilPrefix);

    // make api and model doc path available in mustache template
    additionalProperties.put("apiDocPath", apiDocPath);
    additionalProperties.put("modelDocPath", modelDocPath);

    importMapping.put("List", "java.util.List");

    if (fullJavaUtil) {
      typeMapping.put("array", "java.util.List");
      typeMapping.put("map", "java.util.Map");
      typeMapping.put("DateTime", "java.util.Date");
      typeMapping.remove("List");
      importMapping.remove("Date");
      importMapping.remove("Map");
      importMapping.remove("HashMap");
      importMapping.remove("Array");
      importMapping.remove("ArrayList");
      importMapping.remove("List");
      importMapping.remove("Set");
      importMapping.remove("DateTime");
      instantiationTypes.put("array", "java.util.ArrayList");
      instantiationTypes.put("map", "java.util.HashMap");
    }

    this.sanitizeConfig();

    // optional jackson mappings for BigDecimal support
    importMapping.put(
        "ToStringSerializer", "com.fasterxml.jackson.databind.ser.std.ToStringSerializer");
    importMapping.put("JsonSerialize", "com.fasterxml.jackson.databind.annotation.JsonSerialize");

    // imports for pojos
    importMapping.put("ApiModelProperty", "io.swagger.annotations.ApiModelProperty");
    importMapping.put("ApiModel", "io.swagger.annotations.ApiModel");
    importMapping.put("JsonProperty", "com.fasterxml.jackson.annotation.JsonProperty");
    importMapping.put("JsonValue", "com.fasterxml.jackson.annotation.JsonValue");
    importMapping.put("SerializedName", "com.google.gson.annotations.SerializedName");
    importMapping.put("Objects", "java.util.Objects");
    importMapping.put("StringUtil", invokerPackage + ".StringUtil");

    if (additionalProperties.containsKey(DATE_LIBRARY)) {
      setDateLibrary(additionalProperties.get("dateLibrary").toString());
      additionalProperties.put(dateLibrary, "true");
    }

    if ("joda".equals(dateLibrary)) {
      typeMapping.put("date", "LocalDate");
      typeMapping.put("DateTime", "DateTime");

      importMapping.put("LocalDate", "org.joda.time.LocalDate");
      importMapping.put("DateTime", "org.joda.time.DateTime");
    } else if (dateLibrary.startsWith("java8")) {
      additionalProperties.put("java8", "true");
      typeMapping.put("date", "LocalDate");
      importMapping.put("LocalDate", "java.time.LocalDate");
      if ("java8-localdatetime".equals(dateLibrary)) {
        typeMapping.put("DateTime", "LocalDateTime");
        importMapping.put("LocalDateTime", "java.time.LocalDateTime");
      } else {
        typeMapping.put("DateTime", "OffsetDateTime");
        importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
      }
    }
  }
  @Override
  public void processOpts() {
    super.processOpts();

    if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
      this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
    } else {
      // not set, use default to be passed to template
      additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
    }

    if (additionalProperties.containsKey(CodegenConstants.GROUP_ID)) {
      this.setGroupId((String) additionalProperties.get(CodegenConstants.GROUP_ID));
    } else {
      // not set, use to be passed to template
      additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
    }

    if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_ID)) {
      this.setArtifactId((String) additionalProperties.get(CodegenConstants.ARTIFACT_ID));
    } else {
      // not set, use to be passed to template
      additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
    }

    if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_VERSION)) {
      this.setArtifactVersion((String) additionalProperties.get(CodegenConstants.ARTIFACT_VERSION));
    } else {
      // not set, use to be passed to template
      additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
    }

    if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
      this.setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER));
    }

    if (additionalProperties.containsKey(CodegenConstants.LOCAL_VARIABLE_PREFIX)) {
      this.setLocalVariablePrefix(
          (String) additionalProperties.get(CodegenConstants.LOCAL_VARIABLE_PREFIX));
    }

    if (additionalProperties.containsKey(CodegenConstants.SERIALIZABLE_MODEL)) {
      this.setSerializableModel(
          Boolean.valueOf(
              additionalProperties.get(CodegenConstants.SERIALIZABLE_MODEL).toString()));
    }

    if (additionalProperties.containsKey(CodegenConstants.LIBRARY)) {
      this.setLibrary((String) additionalProperties.get(CodegenConstants.LIBRARY));
    }

    if (additionalProperties.containsKey(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING)) {
      this.setSerializeBigDecimalAsString(
          Boolean.valueOf(
              additionalProperties
                  .get(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING)
                  .toString()));
    }

    // need to put back serializableModel (boolean) into additionalProperties as value in
    // additionalProperties is string
    additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, serializableModel);

    if (additionalProperties.containsKey(FULL_JAVA_UTIL)) {
      this.setFullJavaUtil(Boolean.valueOf(additionalProperties.get(FULL_JAVA_UTIL).toString()));
    }

    if (additionalProperties.containsKey(USE_RX_JAVA)) {
      this.setUseRxJava(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA).toString()));
    }
    if (fullJavaUtil) {
      javaUtilPrefix = "java.util.";
    }
    additionalProperties.put(FULL_JAVA_UTIL, fullJavaUtil);
    additionalProperties.put("javaUtilPrefix", javaUtilPrefix);

    // make api and model doc path available in mustache template
    additionalProperties.put("apiDocPath", apiDocPath);
    additionalProperties.put("modelDocPath", modelDocPath);

    importMapping.put("List", "java.util.List");

    if (fullJavaUtil) {
      typeMapping.put("array", "java.util.List");
      typeMapping.put("map", "java.util.Map");
      typeMapping.put("DateTime", "java.util.Date");
      typeMapping.remove("List");
      importMapping.remove("Date");
      importMapping.remove("Map");
      importMapping.remove("HashMap");
      importMapping.remove("Array");
      importMapping.remove("ArrayList");
      importMapping.remove("List");
      importMapping.remove("Set");
      importMapping.remove("DateTime");
      instantiationTypes.put("array", "java.util.ArrayList");
      instantiationTypes.put("map", "java.util.HashMap");
    }

    this.sanitizeConfig();

    // optional jackson mappings for BigDecimal support
    importMapping.put(
        "ToStringSerializer", "com.fasterxml.jackson.databind.ser.std.ToStringSerializer");
    importMapping.put("JsonSerialize", "com.fasterxml.jackson.databind.annotation.JsonSerialize");

    // imports for pojos
    importMapping.put("ApiModelProperty", "io.swagger.annotations.ApiModelProperty");
    importMapping.put("ApiModel", "io.swagger.annotations.ApiModel");
    importMapping.put("JsonProperty", "com.fasterxml.jackson.annotation.JsonProperty");
    importMapping.put("JsonValue", "com.fasterxml.jackson.annotation.JsonValue");
    importMapping.put("Objects", "java.util.Objects");
    importMapping.put("StringUtil", invokerPackage + ".StringUtil");

    final String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");
    writeOptional(outputFolder, new SupportingFile("pom.mustache", "", "pom.xml"));
    writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md"));
    writeOptional(outputFolder, new SupportingFile("build.gradle.mustache", "", "build.gradle"));
    writeOptional(
        outputFolder, new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
    writeOptional(
        outputFolder, new SupportingFile("gradle.properties.mustache", "", "gradle.properties"));
    writeOptional(
        outputFolder,
        new SupportingFile("manifest.mustache", projectFolder, "AndroidManifest.xml"));
    writeOptional(
        outputFolder, new SupportingFile("ApiClient.mustache", invokerFolder, "ApiClient.java"));
    supportingFiles.add(
        new SupportingFile("StringUtil.mustache", invokerFolder, "StringUtil.java"));

    final String authFolder = (sourceFolder + '/' + invokerPackage + ".auth").replace(".", "/");
    if ("feign".equals(getLibrary())) {
      supportingFiles.add(
          new SupportingFile("FormAwareEncoder.mustache", invokerFolder, "FormAwareEncoder.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"));
    supportingFiles.add(
        new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java"));

    if (!("feign".equals(getLibrary()) || usesAnyRetrofitLibrary())) {
      supportingFiles.add(
          new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java"));
      supportingFiles.add(
          new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java"));
      supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java"));
      supportingFiles.add(
          new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java"));
    }

    // library-specific files
    if (StringUtils.isEmpty(getLibrary())) {
      // generate markdown docs
      modelDocTemplateFiles.put("model_doc.mustache", ".md");
      apiDocTemplateFiles.put("api_doc.mustache", ".md");
    } else if ("okhttp-gson".equals(getLibrary())) {
      // generate markdown docs
      modelDocTemplateFiles.put("model_doc.mustache", ".md");
      apiDocTemplateFiles.put("api_doc.mustache", ".md");
      // the "okhttp-gson" library template requires "ApiCallback.mustache" for async call
      supportingFiles.add(
          new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java"));
      supportingFiles.add(
          new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java"));
      supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
      supportingFiles.add(
          new SupportingFile(
              "ProgressRequestBody.mustache", invokerFolder, "ProgressRequestBody.java"));
      supportingFiles.add(
          new SupportingFile(
              "ProgressResponseBody.mustache", invokerFolder, "ProgressResponseBody.java"));
      // "build.sbt" is for development with SBT
      supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
    } else if (usesAnyRetrofitLibrary()) {
      supportingFiles.add(
          new SupportingFile(
              "auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
      supportingFiles.add(
          new SupportingFile(
              "CollectionFormats.mustache", invokerFolder, "CollectionFormats.java"));
    } else if ("jersey2".equals(getLibrary())) {
      // generate markdown docs
      modelDocTemplateFiles.put("model_doc.mustache", ".md");
      apiDocTemplateFiles.put("api_doc.mustache", ".md");
      supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
    }

    if (additionalProperties.containsKey(DATE_LIBRARY)) {
      this.dateLibrary = additionalProperties.get(DATE_LIBRARY).toString();
    }

    if ("joda".equals(dateLibrary)) {
      typeMapping.put("date", "LocalDate");
      typeMapping.put("DateTime", "DateTime");

      importMapping.put("LocalDate", "org.joda.time.LocalDate");
      importMapping.put("DateTime", "org.joda.time.DateTime");
    } else if ("java8".equals(dateLibrary)) {
      additionalProperties.put("java8", "true");
      additionalProperties.put("javaVersion", "1.8");
      typeMapping.put("date", "LocalDate");
      typeMapping.put("DateTime", "LocalDateTime");
      importMapping.put("LocalDate", "java.time.LocalDate");
      importMapping.put("LocalDateTime", "java.time.LocalDateTime");
    }

    supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
    supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
  }