From 28677e6e095306db9e9441cd2023ef3faf1d112f Mon Sep 17 00:00:00 2001
From: Jim Schubert <james.schubert@gmail.com>
Date: Sun, 14 Jul 2019 22:03:59 -0400
Subject: [PATCH 1/5] [core] Initial support for server variable overrides

---
 README.md                                     |  8 +-
 docs/usage.md                                 | 30 +++---
 .../openapitools/codegen/cmd/Generate.java    | 15 +--
 .../codegen/config/GeneratorSettings.java     | 50 ++++++++--
 .../openapitools/codegen/CodegenConfig.java   |  2 +
 .../openapitools/codegen/DefaultCodegen.java  |  9 +-
 .../codegen/DefaultGenerator.java             |  8 +-
 .../codegen/config/CodegenConfigurator.java   | 36 ++++++-
 .../config/CodegenConfiguratorUtils.java      | 13 +++
 .../codegen/languages/AbstractCppCodegen.java |  2 +-
 .../AbstractJavaJAXRSServerCodegen.java       |  2 +-
 .../languages/AspNetCoreServerCodegen.java    |  2 +-
 .../languages/CSharpNancyFXServerCodegen.java |  2 +-
 .../languages/FsharpGiraffeServerCodegen.java |  2 +-
 .../languages/JavaPKMSTServerCodegen.java     |  2 +-
 .../languages/JavaVertXServerCodegen.java     |  2 +-
 .../languages/KotlinSpringServerCodegen.java  |  2 +-
 .../languages/NodeJSServerCodegen.java        |  2 +-
 .../codegen/languages/RustServerCodegen.java  |  2 +-
 .../codegen/languages/SpringCodegen.java      |  2 +-
 .../codegen/utils/URLPathUtils.java           | 51 ++++++----
 .../codegen/utils/URLPathUtilsTest.java       | 94 ++++++++++++++++---
 22 files changed, 254 insertions(+), 84 deletions(-)

diff --git a/README.md b/README.md
index ab8bce4e671f..fcdeee4666fd 100644
--- a/README.md
+++ b/README.md
@@ -429,7 +429,6 @@ NAME
 SYNOPSIS
         openapi-generator-cli generate
                 [(-a <authorization> | --auth <authorization>)]
-                [--additional-properties <additional properties>...]
                 [--api-package <api package>] [--artifact-id <artifact id>]
                 [--artifact-version <artifact version>]
                 [(-c <configuration file> | --config <configuration file>)]
@@ -450,12 +449,13 @@ SYNOPSIS
                 [--model-name-prefix <model name prefix>]
                 [--model-name-suffix <model name suffix>]
                 [--model-package <model package>]
-                [(-o <output directory> | --output <output directory>)]
+                [(-o <output directory> | --output <output directory>)] 
+                [(-p <additional properties> | --additional-properties <additional properties>)...]
                 [--package-name <package name>] [--release-note <release note>]
                 [--remove-operation-id-prefix]
                 [--reserved-words-mappings <reserved word mappings>...]
-                [(-s | --skip-overwrite)] [--skip-validate-spec]
-                [--strict-spec <true/false strict behavior>]
+                [(-s | --skip-overwrite)] [--server-variables <server variables>...]
+                [--skip-validate-spec] [--strict-spec <true/false strict behavior>]
                 [(-t <template directory> | --template-dir <template directory>)]
                 [--type-mappings <type mappings>...] [(-v | --verbose)]
 
diff --git a/docs/usage.md b/docs/usage.md
index 8e09370b61e4..3881595d4626 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -235,7 +235,6 @@ NAME
 SYNOPSIS
         openapi-generator-cli generate
                 [(-a <authorization> | --auth <authorization>)]
-                [--additional-properties <additional properties>...]
                 [--api-package <api package>] [--artifact-id <artifact id>]
                 [--artifact-version <artifact version>]
                 [(-c <configuration file> | --config <configuration file>)]
@@ -256,15 +255,15 @@ SYNOPSIS
                 [--model-name-prefix <model name prefix>]
                 [--model-name-suffix <model name suffix>]
                 [--model-package <model package>]
-                [(-o <output directory> | --output <output directory>)]
+                [(-o <output directory> | --output <output directory>)] 
+                [(-p <additional properties> | --additional-properties <additional properties>)...]
                 [--package-name <package name>] [--release-note <release note>]
                 [--remove-operation-id-prefix]
                 [--reserved-words-mappings <reserved word mappings>...]
-                [(-s | --skip-overwrite)] [--skip-validate-spec]
-                [--strict-spec <true/false strict behavior>]
+                [(-s | --skip-overwrite)] [--server-variables <server variables>...]
+                [--skip-validate-spec] [--strict-spec <true/false strict behavior>]
                 [(-t <template directory> | --template-dir <template directory>)]
                 [--type-mappings <type mappings>...] [(-v | --verbose)]
-
 ```
 
 <details>
@@ -277,19 +276,16 @@ OPTIONS
             remotely. Pass in a URL-encoded string of name:header with a comma
             separating multiple values
 
-        --additional-properties <additional properties>
-            sets additional properties that can be referenced by the mustache
-            templates in the format of name=value,name=value. You can also have
-            multiple occurrences of this option.
-
         --api-package <api package>
             package for generated api classes
 
         --artifact-id <artifact id>
-            artifactId in generated pom.xml
+            artifactId in generated pom.xml. This also becomes part of the
+            generated library's filename
 
         --artifact-version <artifact version>
-            artifact version in generated pom.xml
+            artifact version in generated pom.xml. This also becomes part of the
+            generated library's filename
 
         -c <configuration file>, --config <configuration file>
             Path to configuration file configuration file. It can be json or
@@ -382,6 +378,12 @@ OPTIONS
         -o <output directory>, --output <output directory>
             where to write the generated files (current dir by default)
 
+        -p <additional properties>, --additional-properties <additional
+        properties>
+            sets additional properties that can be referenced by the mustache
+            templates in the format of name=value,name=value. You can also have
+            multiple occurrences of this option.
+
         --package-name <package name>
             package for generated classes (where supported)
 
@@ -400,6 +402,10 @@ OPTIONS
             specifies if the existing files should be overwritten during the
             generation.
 
+        --server-variables <server variables>
+            sets server variables for spec documents which support variable
+            templating of servers.
+
         --skip-validate-spec
             Skips the default behavior of validating an input specification.
 
diff --git a/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java b/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java
index 00a7f5334869..c75ee928eb91 100644
--- a/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java
+++ b/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java
@@ -18,13 +18,7 @@
 package org.openapitools.codegen.cmd;
 
 import static org.apache.commons.lang3.StringUtils.isNotEmpty;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyImportMappingsKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyInstantiationTypesKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyLanguageSpecificPrimitivesCsvList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyReservedWordsMappingsKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applySystemPropertiesKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyTypeMappingsKvpList;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.*;
 
 import ch.qos.logback.classic.LoggerContext;
 import ch.qos.logback.core.spi.FilterAttachable;
@@ -160,6 +154,12 @@ public class Generate implements Runnable {
                     + " You can also have multiple occurrences of this option.")
     private List<String> importMappings = new ArrayList<>();
 
+    @Option(
+            name = {"--server-variables"},
+            title = "server variables",
+            description = "sets server variables for spec documents which support variable templating of servers.")
+    private List<String> serverVariables = new ArrayList<>();
+
     @Option(name = {"--invoker-package"}, title = "invoker package",
             description = CodegenConstants.INVOKER_PACKAGE_DESC)
     private String invokerPackage;
@@ -393,6 +393,7 @@ public void run() {
         applyAdditionalPropertiesKvpList(additionalProperties, configurator);
         applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator);
         applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator);
+        applyServerVariablesKvpList(serverVariables, configurator);
 
         try {
             final ClientOptInput clientOptInput = configurator.toClientOptInput();
diff --git a/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/GeneratorSettings.java b/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/GeneratorSettings.java
index 565539c7ca34..37d99044ba58 100644
--- a/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/GeneratorSettings.java
+++ b/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/GeneratorSettings.java
@@ -52,6 +52,7 @@ public final class GeneratorSettings implements Serializable {
     private ImmutableMap<String, String> importMappings;
     private ImmutableSet<String> languageSpecificPrimitives;
     private ImmutableMap<String, String> reservedWordMappings;
+    private ImmutableMap<String, String> serverVariables;
 
     private String gitUserId;
     private String gitRepoId;
@@ -245,6 +246,17 @@ public Map<String, String> getReservedWordMappings() {
         return reservedWordMappings;
     }
 
+
+    /**
+     * Gets server variable. Values defined here will be attempted to be replaced within a templated server object.
+     *
+     * @return the server variables
+     */
+    public Map<String, String> getServerVariables() {
+        return serverVariables;
+    }
+
+
     /**
      * Gets git user id. e.g. <strong>openapitools</strong>.
      * <p>
@@ -311,6 +323,7 @@ private GeneratorSettings(Builder builder) {
         importMappings = ImmutableMap.copyOf(builder.importMappings);
         languageSpecificPrimitives = ImmutableSet.copyOf(builder.languageSpecificPrimitives);
         reservedWordMappings = ImmutableMap.copyOf(builder.reservedWordMappings);
+        serverVariables = ImmutableMap.copyOf(builder.serverVariables);
         gitUserId = builder.gitUserId;
         gitRepoId = builder.gitRepoId;
         releaseNote = builder.releaseNote;
@@ -373,6 +386,7 @@ public GeneratorSettings() {
         importMappings = ImmutableMap.of();
         languageSpecificPrimitives = ImmutableSet.of();
         reservedWordMappings = ImmutableMap.of();
+        serverVariables = ImmutableMap.of();
     }
 
     private void setDefaults() {
@@ -394,12 +408,6 @@ public static Builder newBuilder() {
         return new Builder();
     }
 
-    /**
-     * New builder builder.
-     *
-     * @param copy the copy
-     * @return the builder
-     */
     public static Builder newBuilder(GeneratorSettings copy) {
         Builder builder = new Builder();
         builder.generatorName = copy.getGeneratorName();
@@ -419,6 +427,7 @@ public static Builder newBuilder(GeneratorSettings copy) {
         builder.importMappings = new HashMap<>(copy.getImportMappings());
         builder.languageSpecificPrimitives = new HashSet<>(copy.getLanguageSpecificPrimitives());
         builder.reservedWordMappings = new HashMap<>(copy.getReservedWordMappings());
+        builder.serverVariables = new HashMap<>(copy.getServerVariables());
         builder.gitUserId = copy.getGitUserId();
         builder.gitRepoId = copy.getGitRepoId();
         builder.releaseNote = copy.getReleaseNote();
@@ -449,6 +458,7 @@ public static final class Builder {
         private Map<String, String> importMappings;
         private Set<String> languageSpecificPrimitives;
         private Map<String, String> reservedWordMappings;
+        private Map<String, String> serverVariables;
         private String gitUserId;
         private String gitRepoId;
         private String releaseNote;
@@ -464,6 +474,7 @@ public Builder() {
             importMappings = new HashMap<>();
             languageSpecificPrimitives = new HashSet<>();
             reservedWordMappings = new HashMap<>();
+            serverVariables = new HashMap<>();
 
             gitUserId = DEFAULT_GIT_USER_ID;
             gitRepoId = DEFAULT_GIT_REPO_ID;
@@ -617,6 +628,17 @@ public Builder withInstantiationType(String key, String value) {
             return this;
         }
 
+        /**
+         * Sets the {@code serverVariables} and returns a reference to this Builder so that the methods can be chained together.
+         *
+         * @param serverVariables the {@code serverVariables} to set
+         * @return a reference to this Builder
+         */
+        public Builder withServerVariables(Map<String, String> serverVariables) {
+            this.serverVariables = serverVariables;
+            return this;
+        }
+
         /**
          * Sets the {@code typeMappings} and returns a reference to this Builder so that the methods can be chained together.
          *
@@ -731,6 +753,22 @@ public Builder withReservedWordMapping(String key, String value) {
             return this;
         }
 
+
+        /**
+         * Sets a single {@code serverVariables} and returns a reference to this Builder so that the methods can be chained together.
+         *
+         * @param key   A key for some server variable
+         * @param value The value of some server variable to be replaced in a templated server object.
+         * @return a reference to this Builder
+         */
+        public Builder withServerVariable(String key, String value) {
+            if (this.serverVariables == null) {
+                this.serverVariables = new HashMap<>();
+            }
+            this.serverVariables.put(key, value);
+            return this;
+        }
+
         /**
          * Sets the {@code gitUserId} and returns a reference to this Builder so that the methods can be chained together.
          *
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java
index dec7bc751b48..6f0a8dd6f65f 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java
@@ -43,6 +43,8 @@ public interface CodegenConfig {
 
     Map<String, Object> additionalProperties();
 
+    Map<String, String> serverVariables();
+
     Map<String, Object> vendorExtensions();
 
     String testPackage();
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
index 5373b99e934d..7368d3a047bf 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
@@ -88,6 +88,7 @@ public class DefaultCodegen implements CodegenConfig {
     protected String embeddedTemplateDir;
     protected String commonTemplateDir = "_common";
     protected Map<String, Object> additionalProperties = new HashMap<String, Object>();
+    protected Map<String, String> serverVariables = new HashMap<String, String>();
     protected Map<String, Object> vendorExtensions = new HashMap<String, Object>();
     protected List<SupportingFile> supportingFiles = new ArrayList<SupportingFile>();
     protected List<CliOption> cliOptions = new ArrayList<CliOption>();
@@ -456,12 +457,12 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
     public void postProcessParameter(CodegenParameter parameter) {
     }
 
-    //override with any special handling of the entire swagger spec
+    //override with any special handling of the entire OpenAPI spec document
     @SuppressWarnings("unused")
     public void preprocessOpenAPI(OpenAPI openAPI) {
     }
 
-    // override with any special handling of the entire swagger spec
+    // override with any special handling of the entire OpenAPI spec document
     @SuppressWarnings("unused")
     public void processOpenAPI(OpenAPI openAPI) {
     }
@@ -675,6 +676,10 @@ public Map<String, Object> additionalProperties() {
         return additionalProperties;
     }
 
+    public Map<String, String> serverVariables() {
+        return serverVariables;
+    }
+
     public Map<String, Object> vendorExtensions() {
         return vendorExtensions;
     }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
index 8e1e40d79f3c..1b30e4b3709c 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
@@ -207,10 +207,10 @@ private void configureGeneratorProperties() {
             config.vendorExtensions().putAll(openAPI.getExtensions());
         }
 
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, config.serverVariables());
         contextPath = config.escapeText(url.getPath()).replaceAll("/$", ""); // for backward compatibility
         basePathWithoutHost = contextPath;
-        basePath = config.escapeText(URLPathUtils.getHost(openAPI)).replaceAll("/$", "");
+        basePath = config.escapeText(URLPathUtils.getHost(openAPI, config.serverVariables())).replaceAll("/$", "");
     }
 
     private void configureOpenAPIInfo() {
@@ -548,7 +548,7 @@ public int compare(CodegenOperation one, CodegenOperation another) {
                     }
                 });
                 Map<String, Object> operation = processOperations(config, tag, ops, allModels);
-                URL url = URLPathUtils.getServerURL(openAPI);
+                URL url = URLPathUtils.getServerURL(openAPI, config.serverVariables());
                 operation.put("basePath", basePath);
                 operation.put("basePathWithoutHost", config.encodePath(url.getPath()).replaceAll("/$", ""));
                 operation.put("contextPath", contextPath);
@@ -819,7 +819,7 @@ private Map<String, Object> buildSupportFileBundle(List<Object> allOperations, L
         Map<String, Object> apis = new HashMap<String, Object>();
         apis.put("apis", allOperations);
 
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, config.serverVariables());
 
         bundle.put("openAPI", openAPI);
         bundle.put("basePath", basePath);
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java
index 4c251ffc4a0c..bd5c9762877d 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java
@@ -67,6 +67,7 @@ public class CodegenConfigurator {
     private Map<String, String> importMappings = new HashMap<>();
     private Set<String> languageSpecificPrimitives = new HashSet<>();
     private Map<String, String> reservedWordMappings = new HashMap<>();
+    private Map<String, String> serverVariables = new HashMap<>();
     private String auth;
 
     public CodegenConfigurator() {
@@ -98,6 +99,12 @@ public static CodegenConfigurator fromFile(String configFile) {
         return null;
     }
 
+    public CodegenConfigurator addServerVariable(String key, String value) {
+        this.serverVariables.put(key, value);
+        generatorSettingsBuilder.withServerVariable(key, value);
+        return this;
+    }
+
     public CodegenConfigurator addAdditionalProperty(String key, Object value) {
         this.additionalProperties.put(key, value);
         generatorSettingsBuilder.withAdditionalProperty(key, value);
@@ -146,6 +153,18 @@ public CodegenConfigurator setAdditionalProperties(Map<String, Object> additiona
         return this;
     }
 
+    public CodegenConfigurator setServerVariables(Map<String, String> serverVariables) {
+        this.serverVariables = serverVariables;
+        generatorSettingsBuilder.withServerVariables(serverVariables);
+        return this;
+    }
+
+    public CodegenConfigurator setReservedWordsMappings(Map<String, String> reservedWordMappings) {
+        this.reservedWordMappings = reservedWordMappings;
+        generatorSettingsBuilder.withReservedWordMappings(reservedWordMappings);
+        return this;
+    }
+
     public CodegenConfigurator setApiPackage(String apiPackage) {
         generatorSettingsBuilder.withApiPackage(apiPackage);
         return this;
@@ -223,6 +242,7 @@ public CodegenConfigurator setIgnoreFileOverride(final String ignoreFileOverride
     }
 
     public CodegenConfigurator setImportMappings(Map<String, String> importMappings) {
+        this.importMappings = importMappings;
         generatorSettingsBuilder.withImportMappings(importMappings);
         return this;
     }
@@ -234,6 +254,7 @@ public CodegenConfigurator setInputSpec(String inputSpec) {
     }
 
     public CodegenConfigurator setInstantiationTypes(Map<String, String> instantiationTypes) {
+        this.instantiationTypes = instantiationTypes;
         generatorSettingsBuilder.withInstantiationTypes(instantiationTypes);
         return this;
     }
@@ -245,6 +266,7 @@ public CodegenConfigurator setInvokerPackage(String invokerPackage) {
 
     public CodegenConfigurator setLanguageSpecificPrimitives(
             Set<String> languageSpecificPrimitives) {
+        this.languageSpecificPrimitives = languageSpecificPrimitives;
         generatorSettingsBuilder.withLanguageSpecificPrimitives(languageSpecificPrimitives);
         return this;
     }
@@ -294,11 +316,6 @@ public CodegenConfigurator setRemoveOperationIdPrefix(boolean removeOperationIdP
         return this;
     }
 
-    public CodegenConfigurator setReservedWordsMappings(Map<String, String> reservedWordMappings) {
-        generatorSettingsBuilder.withReservedWordMappings(reservedWordMappings);
-        return this;
-    }
-
     public CodegenConfigurator setSkipOverwrite(boolean skipOverwrite) {
         workflowSettingsBuilder.withSkipOverwrite(skipOverwrite);
         return this;
@@ -310,6 +327,7 @@ public CodegenConfigurator setStrictSpecBehavior(boolean strictSpecBehavior) {
     }
 
     public CodegenConfigurator setSystemProperties(Map<String, String> systemProperties) {
+        this.systemProperties = systemProperties;
         workflowSettingsBuilder.withSystemProperties(systemProperties);
         return this;
     }
@@ -326,6 +344,7 @@ public CodegenConfigurator setTemplatingEngineName(String templatingEngineName)
     }
 
     public CodegenConfigurator setTypeMappings(Map<String, String> typeMappings) {
+        this.typeMappings = typeMappings;
         generatorSettingsBuilder.withTypeMappings(typeMappings);
         return this;
     }
@@ -454,6 +473,13 @@ public ClientOptInput toClientOptInput() {
         config.reservedWordsMappings().putAll(generatorSettings.getReservedWordMappings());
         config.additionalProperties().putAll(generatorSettings.getAdditionalProperties());
 
+        Map<String, String> serverVariables = generatorSettings.getServerVariables();
+        if (!serverVariables.isEmpty()) {
+            // This is currently experimental due to vagueness in the specification
+            LOGGER.warn("user-defined server variable support is experimental.");
+            config.serverVariables().putAll(serverVariables);
+        }
+
         ClientOptInput input = new ClientOptInput()
                 .config(config);
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfiguratorUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfiguratorUtils.java
index 14332d738fb2..670869499312 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfiguratorUtils.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfiguratorUtils.java
@@ -107,6 +107,19 @@ public static void applyAdditionalPropertiesKvp(String additionalProperties, Cod
         }
     }
 
+    public static void applyServerVariablesKvpList(List<String> values, CodegenConfigurator configurator) {
+        for(String value : values) {
+            applyServerVariablesKvp(value, configurator);
+        }
+    }
+
+    public static void applyServerVariablesKvp(String values, CodegenConfigurator configurator) {
+        final Map<String, String> map = createMapFromKeyValuePairs(values);
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            configurator.addServerVariable(entry.getKey(), entry.getValue());
+        }
+    }
+
     public static void applyLanguageSpecificPrimitivesCsvList(List<String> languageSpecificPrimitives, CodegenConfigurator configurator) {
         for(String propString : languageSpecificPrimitives) {
             applyLanguageSpecificPrimitivesCsv(propString, configurator);
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java
index 65105e467a86..81605a720ed9 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java
@@ -307,7 +307,7 @@ public void postProcessFile(File file, String fileType) {
     
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         String port = URLPathUtils.getPort(url, "");
         String host = url.getHost();
         if(!port.isEmpty()) {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java
index c15c17418734..94b960e4766d 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java
@@ -110,7 +110,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         */
 
         if (!this.additionalProperties.containsKey(SERVER_PORT)) {
-            URL url = URLPathUtils.getServerURL(openAPI);
+            URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
             // 8080 is the default value for a JEE Server:
             this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, serverPort));
         }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
index ae3ed7e12da7..05bcb9eaf0a5 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
@@ -267,7 +267,7 @@ public String getHelp() {
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
         super.preprocessOpenAPI(openAPI);
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         additionalProperties.put("serverHost", url.getHost());
         additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
     }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java
index 864a21c6f127..e2cfc0b64788 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java
@@ -359,7 +359,7 @@ public String toModelName(final String name) {
 
     @Override
     public void preprocessOpenAPI(final OpenAPI openAPI) {
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         String path = URLPathUtils.getPath(url, "/");
         final String packageContextOption = (String) additionalProperties.get(PACKAGE_CONTEXT);
         additionalProperties.put("packageContext", packageContextOption == null ? sanitizeName(path) : packageContextOption);
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java
index 5a84940292c5..aa56429199c4 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java
@@ -165,7 +165,7 @@ public String getHelp() {
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
         super.preprocessOpenAPI(openAPI);
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         additionalProperties.put("serverHost", url.getHost());
         additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
     }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java
index 292828ef26c5..b88a09f21ff8 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java
@@ -538,7 +538,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
             additionalProperties.put(TITLE, this.title);
         }
 
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
 
         if (openAPI.getPaths() != null) {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java
index a067e29d6bda..8a16bcc60a98 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java
@@ -221,7 +221,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         super.preprocessOpenAPI(openAPI);
 
         // add server port from the swagger file, 8080 by default
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
 
         // retrieve api version from swagger file, 1.0.0-SNAPSHOT by default
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
index 28e45eb7af4d..17c25c91459a 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
@@ -414,7 +414,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         }
 
         if (!additionalProperties.containsKey(SERVER_PORT)) {
-            URL url = URLPathUtils.getServerURL(openAPI);
+            URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
             this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
         }
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java
index 7311569bc5d6..e89746db1a3c 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java
@@ -358,7 +358,7 @@ public void processOpts() {
 
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         String host =  URLPathUtils.getProtocolAndHost(url);
         String port = URLPathUtils.getPort(url, defaultServerPort) ;
         String basePath = url.getPath();
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
index dfbb7eab35de..14a3401f7f89 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
@@ -291,7 +291,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         }
         info.setVersion(StringUtils.join(versionComponents, "."));
 
-        URL url = URLPathUtils.getServerURL(openAPI);
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
         additionalProperties.put("serverHost", url.getHost());
         additionalProperties.put("serverPort", URLPathUtils.getPort(url, 80));
     }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java
index 4b8373004f7c..87d016f89cf6 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java
@@ -507,7 +507,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         }
 
         if(!additionalProperties.containsKey(SERVER_PORT)) {
-            URL url = URLPathUtils.getServerURL(openAPI);
+            URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
             this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
         }
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java
index c72b60f22e95..a27501537535 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java
@@ -17,6 +17,7 @@
 
 package org.openapitools.codegen.utils;
 
+import com.google.common.collect.ImmutableMap;
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.servers.Server;
 import io.swagger.v3.oas.models.servers.ServerVariable;
@@ -28,9 +29,7 @@
 
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -40,24 +39,28 @@ public class URLPathUtils {
     public static final String LOCAL_HOST = "http://localhost";
     public static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{([^\\}]+)\\}");
 
-    public static URL getServerURL(OpenAPI openAPI) {
+    // TODO: This should probably be moved into generator/workflow type rather than a static like this.
+    public static URL getServerURL(OpenAPI openAPI, Map<String, String> userDefinedVariables) {
         final List<Server> servers = openAPI.getServers();
         if (servers == null || servers.isEmpty()) {
             LOGGER.warn("Server information seems not defined in the spec. Default to {}.", LOCAL_HOST);
             return getDefaultUrl();
         }
         // TODO need a way to obtain all server URLs
-        return getServerURL(servers.get(0));
+        return getServerURL(servers.get(0), userDefinedVariables);
     }
 
-    public static URL getServerURL(final Server server) {
+    public static URL getServerURL(final Server server, final Map<String, String> userDefinedVariables) {
         String url = server.getUrl();
         ServerVariables variables = server.getVariables();
         if (variables == null) {
             variables = new ServerVariables();
         }
+
+        Map<String, String> userVariables = userDefinedVariables == null ? new HashMap<>() : ImmutableMap.copyOf(userDefinedVariables);
+
         if (StringUtils.isNotBlank(url)) {
-            url = extractUrl(server, url, variables);
+            url = extractUrl(server, url, variables, userVariables);
             url = sanitizeUrl(url);
 
             try {
@@ -69,26 +72,33 @@ public static URL getServerURL(final Server server) {
         return getDefaultUrl();
     }
 
-    private static String extractUrl(Server server, String url, ServerVariables variables) {
+    private static String extractUrl(Server server, String url, ServerVariables variables, Map<String, String> userVariables) {
         Set<String> replacedVariables = new HashSet<>();
         Matcher matcher = VARIABLE_PATTERN.matcher(url);
         while (matcher.find()) {
             if (!replacedVariables.contains(matcher.group())) {
-                ServerVariable variable = variables.get(matcher.group(1));
+                String variableName = matcher.group(1);
+                ServerVariable variable = variables.get(variableName);
                 String replacement;
                 if (variable != null) {
-                    if (variable.getDefault() != null) {
-                        replacement = variable.getDefault();
-                    } else if (variable.getEnum() != null && !variable.getEnum().isEmpty()) {
-                        replacement = variable.getEnum().get(0);
-                    } else {
-                        LOGGER.warn("No value found for variable '{}' in server definition '{}', default to empty string.", matcher.group(1), server.getUrl());
-                        replacement = "";
+                    String defaultValue = variable.getDefault();
+                    List<String> enumValues = variable.getEnum() == null ? new ArrayList<>() : variable.getEnum();
+                    if (defaultValue == null && !enumValues.isEmpty()) {
+                       defaultValue = enumValues.get(0);
+                    } else if (defaultValue == null) {
+                        defaultValue = "";
                     }
+
+                    replacement = userVariables.getOrDefault(variableName, defaultValue);
                 } else {
-                    LOGGER.warn("No variable '{}' found in server definition '{}', default to empty string.", matcher.group(1), server.getUrl());
+                    replacement = userVariables.getOrDefault(variableName, "");
+                }
+
+                if (StringUtils.isEmpty(replacement)) {
                     replacement = "";
+                    LOGGER.warn("No value found for variable '{}' in server definition '{}' and no user override specified, default to empty string.", variableName, server.getUrl());
                 }
+
                 url = url.replace(matcher.group(), replacement);
                 replacedVariables.add(matcher.group());
                 matcher = VARIABLE_PATTERN.matcher(url);
@@ -98,7 +108,7 @@ private static String extractUrl(Server server, String url, ServerVariables vari
     }
 
     public static String getScheme(OpenAPI openAPI, CodegenConfig config) {
-        URL url = getServerURL(openAPI);
+        URL url = getServerURL(openAPI, config.serverVariables());
         return getScheme(url, config);
     }
 
@@ -176,11 +186,12 @@ public static String getProtocolAndHost(URL url) {
      * Return the first complete URL from the OpenAPI specification
      *
      * @param openAPI current OpenAPI specification
+     * @param userDefinedVariables User overrides for server variable templating
      * @return host
      */
-    public static String getHost(OpenAPI openAPI) {
+    public static String getHost(OpenAPI openAPI, final Map<String, String> userDefinedVariables) {
         if (openAPI.getServers() != null && openAPI.getServers().size() > 0) {
-            return sanitizeUrl(getServerURL(openAPI.getServers().get(0)).toString());
+            return sanitizeUrl(getServerURL(openAPI.getServers().get(0), userDefinedVariables).toString());
         }
         return LOCAL_HOST;
     }
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/URLPathUtilsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/URLPathUtilsTest.java
index b2e615730776..0d73177053c2 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/URLPathUtilsTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/URLPathUtilsTest.java
@@ -26,13 +26,15 @@
 
 import java.net.URL;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 
 public class URLPathUtilsTest {
 
     @Test
     public void testDefaultValues() {
         OpenAPI openAPI = new OpenAPI();
-        URL serverURL = URLPathUtils.getServerURL(openAPI);
+        URL serverURL = URLPathUtils.getServerURL(openAPI, null);
 
         Assert.assertEquals(serverURL.getHost(), "localhost");
         Assert.assertEquals(serverURL.getPort(), -1);
@@ -47,7 +49,7 @@ public void testDefaultValues() {
     public void testUrl() {
         OpenAPI openAPI = new OpenAPI();
         openAPI.addServersItem(new Server().url("https://abcdef.xyz:9999/some/path"));
-        URL serverURL = URLPathUtils.getServerURL(openAPI);
+        URL serverURL = URLPathUtils.getServerURL(openAPI, null);
 
         Assert.assertEquals(serverURL.getHost(), "abcdef.xyz");
         Assert.assertEquals(serverURL.getPort(), 9999);
@@ -74,51 +76,117 @@ public void testSanitizeUrl() {
             OpenAPI openAPI = new OpenAPI();
             openAPI.addServersItem(new Server().url(t[0]));
 
-            Assert.assertEquals(URLPathUtils.getServerURL(openAPI).toString(), t[1]);
+            Assert.assertEquals(URLPathUtils.getServerURL(openAPI, null).toString(), t[1]);
         }
     }
 
     @Test
     public void testGetServerURLWithVariables() {
         Server s1 = new Server().url("http://localhost:{port}/").variables(new ServerVariables().addServerVariable("port", new ServerVariable()._default("8080").description("the server port")));
-        Assert.assertEquals(URLPathUtils.getServerURL(s1).toString(), "http://localhost:8080/");
+        Assert.assertEquals(URLPathUtils.getServerURL(s1, null).toString(), "http://localhost:8080/");
 
         Server s2 = new Server().url("http://{version}.test.me/{version}").variables(new ServerVariables().addServerVariable("version", new ServerVariable()._default("v1")));
-        Assert.assertEquals(URLPathUtils.getServerURL(s2).toString(), "http://v1.test.me/v1");
+        Assert.assertEquals(URLPathUtils.getServerURL(s2, null).toString(), "http://v1.test.me/v1");
 
         Server s3 = new Server().url("http://localhost:{port}/{version}").variables(
                     new ServerVariables().addServerVariable("version", new ServerVariable()._default("v4"))
                         .addServerVariable("port", new ServerVariable()._default("8080"))
                         .addServerVariable("other", new ServerVariable()._default("something"))
                 );
-        Assert.assertEquals(URLPathUtils.getServerURL(s3).toString(), "http://localhost:8080/v4");
+        Assert.assertEquals(URLPathUtils.getServerURL(s3, null).toString(), "http://localhost:8080/v4");
 
         Server s4 = new Server().url("http://91.161.147.64/{targetEnv}").variables(new ServerVariables().addServerVariable("targetEnv", new ServerVariable().description("target environment")._enum(Arrays.asList("dev", "int", "prd"))._default("prd")));
-        Assert.assertEquals(URLPathUtils.getServerURL(s4).toString(), "http://91.161.147.64/prd");
+        Assert.assertEquals(URLPathUtils.getServerURL(s4, null).toString(), "http://91.161.147.64/prd");
 
         Server s5 = new Server().url("https://api.stats.com/{country1}").variables(new ServerVariables().addServerVariable("country1", new ServerVariable()._enum(Arrays.asList("france", "germany", "italy"))));
-        Assert.assertEquals(URLPathUtils.getServerURL(s5).toString(), "https://api.stats.com/france");
+        Assert.assertEquals(URLPathUtils.getServerURL(s5, null).toString(), "https://api.stats.com/france");
 
         Server s6 = new Server().url("https://api.example.com/{wrong}");
-        Assert.assertEquals(URLPathUtils.getServerURL(s6).toString(), "https://api.example.com/");
+        Assert.assertEquals(URLPathUtils.getServerURL(s6, null).toString(), "https://api.example.com/");
 
         Server s7 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables());
-        Assert.assertEquals(URLPathUtils.getServerURL(s7).toString(), "https://api.example.com/");
+        Assert.assertEquals(URLPathUtils.getServerURL(s7, null).toString(), "https://api.example.com/");
 
         Server s8 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables().addServerVariable("other", new ServerVariable()._default("something")));
-        Assert.assertEquals(URLPathUtils.getServerURL(s8).toString(), "https://api.example.com/");
+        Assert.assertEquals(URLPathUtils.getServerURL(s8, null).toString(), "https://api.example.com/");
 
         Server s9 = new Server().url("https://{user}.example.com/{version}").variables(
                     new ServerVariables().addServerVariable("version", new ServerVariable()._default("v1"))
                         .addServerVariable("user", new ServerVariable()._default("{user}")));
-        Assert.assertEquals(URLPathUtils.getServerURL(s9).toString(), "https://{user}.example.com/v1");
+        Assert.assertEquals(URLPathUtils.getServerURL(s9, null).toString(), "https://{user}.example.com/v1");
+    }
+
+    private ServerVariables serverVariables(String... entries) {
+        ServerVariables variables = new ServerVariables();
+        for (int i = 0; i < entries.length; i+=2) {
+            String key = entries[i];
+            String value = "";
+            if (i+1 < entries.length) {
+                value = entries[i+1];
+            }
+            variables.addServerVariable(key, new ServerVariable()._default(value).description("variable for: " + key));
+        }
+        return variables;
+    }
+
+    @Test
+    public void testGetServerURLWithVariablesAndUserOverrides() {
+        Server s1 = new Server().url("http://localhost:{port}/").variables(
+                serverVariables("port", "8080")
+        );
+        Assert.assertEquals(URLPathUtils.getServerURL(s1, new HashMap<String, String>() {{ put("port", "1234"); }}).toString(), "http://localhost:1234/");
+
+        Server s2 = new Server().url("http://{version}.test.me/{version}").variables(
+                serverVariables("version", "v1")
+        );
+        Assert.assertEquals(URLPathUtils.getServerURL(s2, new HashMap<String, String>() {{ put("version", "v2" ); }}).toString(), "http://v2.test.me/v2");
+
+        Server s3 = new Server().url("http://localhost:{port}/{version}").variables(
+                serverVariables(
+                        "version", "v4",
+                        "port", "8080",
+                        "other", "something"
+                )
+        );
+        Assert.assertEquals(URLPathUtils.getServerURL(s3, new HashMap<String, String>() {{ put("port", "5678"); }}).toString(), "http://localhost:5678/v4");
+
+        Server s4 = new Server().url("http://91.161.147.64/{targetEnv}").variables(
+                new ServerVariables().addServerVariable("targetEnv", new ServerVariable().description("target environment")._enum(Arrays.asList("dev", "int", "prd"))._default("prd")));
+        Assert.assertEquals(URLPathUtils.getServerURL(s4, new HashMap<String, String>() {{ put("targetEnv", "int" ); }}).toString(), "http://91.161.147.64/int");
+
+        Server s5 = new Server().url("https://api.stats.com/{country1}").variables(
+                new ServerVariables().addServerVariable("country1", new ServerVariable()._enum(Arrays.asList("france", "germany", "italy")))
+        );
+        Assert.assertEquals(URLPathUtils.getServerURL(s5, new HashMap<String, String>() {{ put("country1", "italy" ); }}).toString(), "https://api.stats.com/italy");
+
+        Server s6 = new Server().url("https://api.example.com/{wrong}");
+        Assert.assertEquals(URLPathUtils.getServerURL(s6, new HashMap<String, String>() {{ put("port", "8080" ); }}).toString(), "https://api.example.com/");
+
+        Server s7 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables());
+        Assert.assertEquals(URLPathUtils.getServerURL(s7, new HashMap<String, String>() {{ put("", "8080" ); }}).toString(), "https://api.example.com/");
+
+        Server s8 = new Server().url("https://api.example.com/{wrong}").variables(
+                serverVariables("other", "something")
+        );
+        Assert.assertEquals(URLPathUtils.getServerURL(s8, new HashMap<String, String>() {{ put("something", "other" ); }}).toString(), "https://api.example.com/");
+
+        Server s9 = new Server().url("https://{user}.example.com/{version}").variables(
+                serverVariables(
+                        "version", "v1",
+                        "user", "{user}"
+                )
+        );
+        Assert.assertEquals(URLPathUtils.getServerURL(s9, new HashMap<String, String>() {{
+            put("version", "v2" );
+            put("user", "jim");
+        }}).toString(), "https://jim.example.com/v2");
     }
 
     @Test
     public void useDefaultUrlWhenServerUrlIsNull() {
         Server server = new Server().url(null);
 
-        URL serverURL = URLPathUtils.getServerURL(server);
+        URL serverURL = URLPathUtils.getServerURL(server, null);
         Assert.assertEquals(serverURL.toString(), "http://localhost");
     }
 }

From 5ea0a83c476cc8ff9b0c7f9ddd95aac75618dc59 Mon Sep 17 00:00:00 2001
From: Jim Schubert <james.schubert@gmail.com>
Date: Sun, 14 Jul 2019 22:34:30 -0400
Subject: [PATCH 2/5] [gradle] Support user overrides for serverVariables

---
 .../openapi-generator-gradle-plugin/build.gradle    |  1 +
 .../gradle/plugin/OpenApiGeneratorPlugin.kt         |  1 +
 .../extensions/OpenApiGeneratorGenerateExtension.kt |  5 +++++
 .../generator/gradle/plugin/tasks/GenerateTask.kt   | 13 +++++++++++++
 4 files changed, 20 insertions(+)

diff --git a/modules/openapi-generator-gradle-plugin/build.gradle b/modules/openapi-generator-gradle-plugin/build.gradle
index cac4261ea745..442ad536754f 100644
--- a/modules/openapi-generator-gradle-plugin/build.gradle
+++ b/modules/openapi-generator-gradle-plugin/build.gradle
@@ -1,6 +1,7 @@
 buildscript {
     ext.kotlin_version = '1.2.61'
     repositories {
+        mavenLocal()
         mavenCentral()
         maven {
             url "https://plugins.gradle.org/m2/"
diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt
index 8d8e96500970..21514aa25939 100644
--- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt
+++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt
@@ -99,6 +99,7 @@ class OpenApiGeneratorPlugin : Plugin<Project> {
                     instantiationTypes.set(generate.instantiationTypes)
                     typeMappings.set(generate.typeMappings)
                     additionalProperties.set(generate.additionalProperties)
+                    serverVariables.set(generate.serverVariables)
                     languageSpecificPrimitives.set(generate.languageSpecificPrimitives)
                     importMappings.set(generate.importMappings)
                     invokerPackage.set(generate.invokerPackage)
diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt
index a533eca90b77..fe44ddaf26de 100644
--- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt
+++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt
@@ -120,6 +120,11 @@ open class OpenApiGeneratorGenerateExtension(project: Project) {
      */
     val additionalProperties = project.objects.property<Map<String, String>>()
 
+    /**
+     * Sets server variable for server URL template substitution, in the format of name=value,name=value.
+     */
+    val serverVariables = project.objects.property<Map<String, String>>()
+
     /**
      * Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double.
      */
diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt
index 79e20d867ab8..7f6be14382fa 100644
--- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt
+++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt
@@ -155,6 +155,13 @@ open class GenerateTask : DefaultTask() {
     @get:Internal
     val additionalProperties = project.objects.property<Map<String, String>>()
 
+    /**
+     * Sets server variable for server URL template substitution, in the format of name=value,name=value.
+     * You can also have multiple occurrences of this option.
+     */
+    @get:Internal
+    val serverVariables = project.objects.property<Map<String, String>>()
+
     /**
      * Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double.
      */
@@ -573,6 +580,12 @@ open class GenerateTask : DefaultTask() {
                 }
             }
 
+            if (serverVariables.isPresent) {
+                serverVariables.get().forEach { entry ->
+                    configurator.addServerVariable(entry.key, entry.value)
+                }
+            }
+
             if (languageSpecificPrimitives.isPresent) {
                 languageSpecificPrimitives.get().forEach {
                     configurator.addLanguageSpecificPrimitive(it)

From 0b887f8c0a5736141e5d1356428d89c9a15876dd Mon Sep 17 00:00:00 2001
From: Jim Schubert <james.schubert@gmail.com>
Date: Sun, 14 Jul 2019 22:34:43 -0400
Subject: [PATCH 3/5] [maven] Support user overrides for serverVariables

---
 .../codegen/plugin/CodeGenMojo.java           | 27 ++++++++++---------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
index 64bd4f92c154..b330d3170ae8 100644
--- a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
+++ b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
@@ -17,19 +17,8 @@
 
 package org.openapitools.codegen.plugin;
 
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvp;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyImportMappingsKvp;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyInstantiationTypesKvp;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyLanguageSpecificPrimitivesCsv;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyTypeMappingsKvp;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyReservedWordsMappingsKvp;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyImportMappingsKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyInstantiationTypesKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyLanguageSpecificPrimitivesCsvList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyTypeMappingsKvpList;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyReservedWordsMappingsKvpList;
 import static org.apache.commons.lang3.StringUtils.isNotEmpty;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.*;
 
 import java.io.File;
 import java.util.HashMap;
@@ -289,6 +278,12 @@ public class CodeGenMojo extends AbstractMojo {
     @Parameter(name = "additionalProperties", property = "openapi.generator.maven.plugin.additionalProperties")
     private List<String> additionalProperties;
 
+    /**
+     * A map of server variable overrides for specs that support server URL templating
+     */
+    @Parameter(name = "serverVariables", property = "openapi.generator.maven.plugin.serverVariables")
+    private List<String> serverVariables;
+
     /**
      * A map of reserved names and how they should be escaped
      */
@@ -615,6 +610,10 @@ public void execute() throws MojoExecutionException {
                             configurator);
                 }
 
+                if (serverVariables == null && configOptions.containsKey("server-variables")) {
+                    applyServerVariablesKvp(configOptions.get("server-variables").toString(), configurator);
+                }
+
                 // Retained for backwards-compataibility with configOptions -> reserved-words-mappings
                 if (reservedWordsMappings == null && configOptions.containsKey("reserved-words-mappings")) {
                     applyReservedWordsMappingsKvp(configOptions.get("reserved-words-mappings")
@@ -648,6 +647,10 @@ public void execute() throws MojoExecutionException {
                 applyAdditionalPropertiesKvpList(additionalProperties, configurator);
             }
 
+            if (serverVariables != null && (configOptions == null || !configOptions.containsKey("server-variables"))) {
+                applyServerVariablesKvpList(serverVariables, configurator);
+            }
+
             // Apply Reserved Words Mappings
             if (reservedWordsMappings != null && (configOptions == null || !configOptions.containsKey("reserved-words-mappings"))) {
                 applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator);

From 16d4501c4c2f0c6b54a887968bd9ecf68a7b46d0 Mon Sep 17 00:00:00 2001
From: Jim Schubert <james.schubert@gmail.com>
Date: Tue, 16 Jul 2019 12:44:32 -0400
Subject: [PATCH 4/5] [core] Clarify server variable overrides, and propagate
 them to templates in the "servers" array

---
 .../openapitools/codegen/cmd/Generate.java    |  6 ++---
 .../codegen/plugin/CodeGenMojo.java           |  2 +-
 .../openapitools/codegen/CodegenConfig.java   |  2 +-
 .../codegen/CodegenServerVariable.java        |  1 +
 .../openapitools/codegen/DefaultCodegen.java  | 24 +++++++++++++++++--
 .../codegen/DefaultGenerator.java             | 10 ++++----
 .../codegen/config/CodegenConfigurator.java   |  2 +-
 .../codegen/languages/AbstractCppCodegen.java |  2 +-
 .../AbstractJavaJAXRSServerCodegen.java       |  2 +-
 .../languages/AspNetCoreServerCodegen.java    |  2 +-
 .../languages/CSharpNancyFXServerCodegen.java |  2 +-
 .../languages/FsharpGiraffeServerCodegen.java |  8 +------
 .../languages/JavaPKMSTServerCodegen.java     |  2 +-
 .../languages/JavaVertXServerCodegen.java     |  2 +-
 .../languages/KotlinSpringServerCodegen.java  |  2 +-
 .../languages/NodeJSServerCodegen.java        |  2 +-
 .../codegen/languages/RustServerCodegen.java  |  4 +---
 .../codegen/languages/SpringCodegen.java      |  2 +-
 .../codegen/utils/URLPathUtils.java           |  6 ++++-
 19 files changed, 51 insertions(+), 32 deletions(-)

diff --git a/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java b/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java
index c75ee928eb91..929a1334141d 100644
--- a/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java
+++ b/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java
@@ -157,8 +157,8 @@ public class Generate implements Runnable {
     @Option(
             name = {"--server-variables"},
             title = "server variables",
-            description = "sets server variables for spec documents which support variable templating of servers.")
-    private List<String> serverVariables = new ArrayList<>();
+            description = "sets server variables overrides for spec documents which support variable templating of servers.")
+    private List<String> serverVariableOverrides = new ArrayList<>();
 
     @Option(name = {"--invoker-package"}, title = "invoker package",
             description = CodegenConstants.INVOKER_PACKAGE_DESC)
@@ -393,7 +393,7 @@ public void run() {
         applyAdditionalPropertiesKvpList(additionalProperties, configurator);
         applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator);
         applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator);
-        applyServerVariablesKvpList(serverVariables, configurator);
+        applyServerVariablesKvpList(serverVariableOverrides, configurator);
 
         try {
             final ClientOptInput clientOptInput = configurator.toClientOptInput();
diff --git a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
index b330d3170ae8..3723ddec5d22 100644
--- a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
+++ b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
@@ -281,7 +281,7 @@ public class CodeGenMojo extends AbstractMojo {
     /**
      * A map of server variable overrides for specs that support server URL templating
      */
-    @Parameter(name = "serverVariables", property = "openapi.generator.maven.plugin.serverVariables")
+    @Parameter(name = "serverVariableOverrides", property = "openapi.generator.maven.plugin.serverVariableOverrides")
     private List<String> serverVariables;
 
     /**
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java
index 6f0a8dd6f65f..f7141d1fe075 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java
@@ -43,7 +43,7 @@ public interface CodegenConfig {
 
     Map<String, Object> additionalProperties();
 
-    Map<String, String> serverVariables();
+    Map<String, String> serverVariableOverrides();
 
     Map<String, Object> vendorExtensions();
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenServerVariable.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenServerVariable.java
index 15e9db55b67a..15ae1ca15b1d 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenServerVariable.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenServerVariable.java
@@ -7,4 +7,5 @@ public class CodegenServerVariable {
     public String defaultValue;
     public String description;
     public List<String> enumValues;
+    public String value;
 }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
index 7368d3a047bf..2ec8d0698050 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
@@ -676,7 +676,7 @@ public Map<String, Object> additionalProperties() {
         return additionalProperties;
     }
 
-    public Map<String, String> serverVariables() {
+    public Map<String, String> serverVariableOverrides() {
         return serverVariables;
     }
 
@@ -4958,14 +4958,34 @@ public List<CodegenServerVariable> fromServerVariables(Map<String, ServerVariabl
         if (variables == null) {
             return Collections.emptyList();
         }
+
+        Map<String, String> variableOverrides = serverVariableOverrides();
+
         List<CodegenServerVariable> codegenServerVariables = new LinkedList<>();
         for (Entry<String, ServerVariable> variableEntry : variables.entrySet()) {
             CodegenServerVariable codegenServerVariable = new CodegenServerVariable();
             ServerVariable variable = variableEntry.getValue();
+            List<String> enums = variable.getEnum();
+
             codegenServerVariable.defaultValue = variable.getDefault();
             codegenServerVariable.description = escapeText(variable.getDescription());
-            codegenServerVariable.enumValues = variable.getEnum();
+            codegenServerVariable.enumValues = enums;
             codegenServerVariable.name = variableEntry.getKey();
+
+            // Sets the override value for a server variable pattern.
+            // NOTE: OpenAPI Specification doesn't prevent multiple server URLs with variables. If multiple objects have the same
+            //       variables pattern, user overrides will apply to _all_ of these patterns. We may want to consider indexed overrides.
+            if (variableOverrides != null && !variableOverrides.isEmpty()) {
+                String value = variableOverrides.getOrDefault(variableEntry.getKey(), variable.getDefault());
+                codegenServerVariable.value = value;
+
+                if (enums != null && !enums.isEmpty() && !enums.contains(value)) {
+                    LOGGER.warn("Variable override of '{}' is not listed in the enum of allowed values ({}).", value, StringUtils.join(enums, ","));
+                }
+            } else {
+                codegenServerVariable.value = variable.getDefault();
+            }
+
             codegenServerVariables.add(codegenServerVariable);
         }
         return codegenServerVariables;
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
index 1b30e4b3709c..178fdad19902 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
@@ -207,10 +207,12 @@ private void configureGeneratorProperties() {
             config.vendorExtensions().putAll(openAPI.getExtensions());
         }
 
-        URL url = URLPathUtils.getServerURL(openAPI, config.serverVariables());
+        // TODO: Allow user to define _which_ servers object in the array to target.
+        // Configures contextPath/basePath according to api document's servers
+        URL url = URLPathUtils.getServerURL(openAPI, config.serverVariableOverrides());
         contextPath = config.escapeText(url.getPath()).replaceAll("/$", ""); // for backward compatibility
         basePathWithoutHost = contextPath;
-        basePath = config.escapeText(URLPathUtils.getHost(openAPI, config.serverVariables())).replaceAll("/$", "");
+        basePath = config.escapeText(URLPathUtils.getHost(openAPI, config.serverVariableOverrides())).replaceAll("/$", "");
     }
 
     private void configureOpenAPIInfo() {
@@ -548,7 +550,7 @@ public int compare(CodegenOperation one, CodegenOperation another) {
                     }
                 });
                 Map<String, Object> operation = processOperations(config, tag, ops, allModels);
-                URL url = URLPathUtils.getServerURL(openAPI, config.serverVariables());
+                URL url = URLPathUtils.getServerURL(openAPI, config.serverVariableOverrides());
                 operation.put("basePath", basePath);
                 operation.put("basePathWithoutHost", config.encodePath(url.getPath()).replaceAll("/$", ""));
                 operation.put("contextPath", contextPath);
@@ -819,7 +821,7 @@ private Map<String, Object> buildSupportFileBundle(List<Object> allOperations, L
         Map<String, Object> apis = new HashMap<String, Object>();
         apis.put("apis", allOperations);
 
-        URL url = URLPathUtils.getServerURL(openAPI, config.serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, config.serverVariableOverrides());
 
         bundle.put("openAPI", openAPI);
         bundle.put("basePath", basePath);
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java
index bd5c9762877d..566637f433b1 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java
@@ -477,7 +477,7 @@ public ClientOptInput toClientOptInput() {
         if (!serverVariables.isEmpty()) {
             // This is currently experimental due to vagueness in the specification
             LOGGER.warn("user-defined server variable support is experimental.");
-            config.serverVariables().putAll(serverVariables);
+            config.serverVariableOverrides().putAll(serverVariables);
         }
 
         ClientOptInput input = new ClientOptInput()
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java
index 81605a720ed9..017200c2331b 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java
@@ -307,7 +307,7 @@ public void postProcessFile(File file, String fileType) {
     
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         String port = URLPathUtils.getPort(url, "");
         String host = url.getHost();
         if(!port.isEmpty()) {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java
index 94b960e4766d..f7c086596658 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaJAXRSServerCodegen.java
@@ -110,7 +110,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         */
 
         if (!this.additionalProperties.containsKey(SERVER_PORT)) {
-            URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+            URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
             // 8080 is the default value for a JEE Server:
             this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, serverPort));
         }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
index 05bcb9eaf0a5..bd1efe4f9916 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
@@ -267,7 +267,7 @@ public String getHelp() {
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
         super.preprocessOpenAPI(openAPI);
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         additionalProperties.put("serverHost", url.getHost());
         additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
     }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java
index e2cfc0b64788..c95fdcde9b3c 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNancyFXServerCodegen.java
@@ -359,7 +359,7 @@ public String toModelName(final String name) {
 
     @Override
     public void preprocessOpenAPI(final OpenAPI openAPI) {
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         String path = URLPathUtils.getPath(url, "/");
         final String packageContextOption = (String) additionalProperties.get(PACKAGE_CONTEXT);
         additionalProperties.put("packageContext", packageContextOption == null ? sanitizeName(path) : packageContextOption);
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java
index aa56429199c4..8bbb27912a41 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/FsharpGiraffeServerCodegen.java
@@ -23,20 +23,14 @@
 import org.openapitools.codegen.CodegenOperation;
 import org.openapitools.codegen.CodegenType;
 import org.openapitools.codegen.SupportingFile;
-import org.openapitools.codegen.CodegenModel;
-import org.openapitools.codegen.CodegenProperty;
 import org.openapitools.codegen.utils.URLPathUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.net.URL;
-import java.util.Arrays;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
-import java.util.List;
-import java.util.ArrayList;
 
 import static java.util.UUID.randomUUID;
 
@@ -165,7 +159,7 @@ public String getHelp() {
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
         super.preprocessOpenAPI(openAPI);
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         additionalProperties.put("serverHost", url.getHost());
         additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
     }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java
index b88a09f21ff8..e23d9237d061 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaPKMSTServerCodegen.java
@@ -538,7 +538,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
             additionalProperties.put(TITLE, this.title);
         }
 
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
 
         if (openAPI.getPaths() != null) {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java
index 8a16bcc60a98..d0e1cf14c0a7 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaVertXServerCodegen.java
@@ -221,7 +221,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         super.preprocessOpenAPI(openAPI);
 
         // add server port from the swagger file, 8080 by default
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
 
         // retrieve api version from swagger file, 1.0.0-SNAPSHOT by default
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
index 17c25c91459a..cccaebe8ad35 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
@@ -414,7 +414,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         }
 
         if (!additionalProperties.containsKey(SERVER_PORT)) {
-            URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+            URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
             this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
         }
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java
index e89746db1a3c..108aa7a788c5 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSServerCodegen.java
@@ -358,7 +358,7 @@ public void processOpts() {
 
     @Override
     public void preprocessOpenAPI(OpenAPI openAPI) {
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         String host =  URLPathUtils.getProtocolAndHost(url);
         String port = URLPathUtils.getPort(url, defaultServerPort) ;
         String basePath = url.getPath();
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
index 14a3401f7f89..077db23513a7 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
@@ -24,9 +24,7 @@
 import io.swagger.v3.oas.models.media.ArraySchema;
 import io.swagger.v3.oas.models.media.FileSchema;
 import io.swagger.v3.oas.models.media.Schema;
-import io.swagger.v3.oas.models.media.StringSchema;
 import io.swagger.v3.oas.models.media.XML;
-import io.swagger.v3.oas.models.parameters.Parameter;
 import io.swagger.v3.oas.models.parameters.RequestBody;
 import io.swagger.v3.oas.models.servers.Server;
 import org.apache.commons.lang3.StringUtils;
@@ -291,7 +289,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         }
         info.setVersion(StringUtils.join(versionComponents, "."));
 
-        URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+        URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
         additionalProperties.put("serverHost", url.getHost());
         additionalProperties.put("serverPort", URLPathUtils.getPort(url, 80));
     }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java
index 87d016f89cf6..ad57867bd502 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java
@@ -507,7 +507,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
         }
 
         if(!additionalProperties.containsKey(SERVER_PORT)) {
-            URL url = URLPathUtils.getServerURL(openAPI, serverVariables());
+            URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
             this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
         }
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java
index a27501537535..fffccddd907b 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/URLPathUtils.java
@@ -90,6 +90,10 @@ private static String extractUrl(Server server, String url, ServerVariables vari
                     }
 
                     replacement = userVariables.getOrDefault(variableName, defaultValue);
+
+                    if (!enumValues.isEmpty() && !enumValues.contains(replacement)) {
+                        LOGGER.warn("Variable override of '{}' is not listed in the enum of allowed values ({}).", replacement, StringUtils.join(enumValues, ","));
+                    }
                 } else {
                     replacement = userVariables.getOrDefault(variableName, "");
                 }
@@ -108,7 +112,7 @@ private static String extractUrl(Server server, String url, ServerVariables vari
     }
 
     public static String getScheme(OpenAPI openAPI, CodegenConfig config) {
-        URL url = getServerURL(openAPI, config.serverVariables());
+        URL url = getServerURL(openAPI, config.serverVariableOverrides());
         return getScheme(url, config);
     }
 

From f119770e711c5afdf0c9c88c143382b93025bd75 Mon Sep 17 00:00:00 2001
From: Jim Schubert <james.schubert@gmail.com>
Date: Sun, 11 Aug 2019 09:05:06 -0400
Subject: [PATCH 5/5] Temporarily remove serverVariables support in maven
 plugin

---
 .../codegen/plugin/CodeGenMojo.java           | 35 +++++++++----------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
index 3723ddec5d22..201f605fa535 100644
--- a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
+++ b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java
@@ -17,8 +17,19 @@
 
 package org.openapitools.codegen.plugin;
 
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvp;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyImportMappingsKvp;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyInstantiationTypesKvp;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyLanguageSpecificPrimitivesCsv;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyTypeMappingsKvp;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyReservedWordsMappingsKvp;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvpList;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyImportMappingsKvpList;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyInstantiationTypesKvpList;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyLanguageSpecificPrimitivesCsvList;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyTypeMappingsKvpList;
+import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyReservedWordsMappingsKvpList;
 import static org.apache.commons.lang3.StringUtils.isNotEmpty;
-import static org.openapitools.codegen.config.CodegenConfiguratorUtils.*;
 
 import java.io.File;
 import java.util.HashMap;
@@ -278,12 +289,6 @@ public class CodeGenMojo extends AbstractMojo {
     @Parameter(name = "additionalProperties", property = "openapi.generator.maven.plugin.additionalProperties")
     private List<String> additionalProperties;
 
-    /**
-     * A map of server variable overrides for specs that support server URL templating
-     */
-    @Parameter(name = "serverVariableOverrides", property = "openapi.generator.maven.plugin.serverVariableOverrides")
-    private List<String> serverVariables;
-
     /**
      * A map of reserved names and how they should be escaped
      */
@@ -610,10 +615,6 @@ public void execute() throws MojoExecutionException {
                             configurator);
                 }
 
-                if (serverVariables == null && configOptions.containsKey("server-variables")) {
-                    applyServerVariablesKvp(configOptions.get("server-variables").toString(), configurator);
-                }
-
                 // Retained for backwards-compataibility with configOptions -> reserved-words-mappings
                 if (reservedWordsMappings == null && configOptions.containsKey("reserved-words-mappings")) {
                     applyReservedWordsMappingsKvp(configOptions.get("reserved-words-mappings")
@@ -647,10 +648,6 @@ public void execute() throws MojoExecutionException {
                 applyAdditionalPropertiesKvpList(additionalProperties, configurator);
             }
 
-            if (serverVariables != null && (configOptions == null || !configOptions.containsKey("server-variables"))) {
-                applyServerVariablesKvpList(serverVariables, configurator);
-            }
-
             // Apply Reserved Words Mappings
             if (reservedWordsMappings != null && (configOptions == null || !configOptions.containsKey("reserved-words-mappings"))) {
                 applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator);
@@ -701,10 +698,10 @@ public void execute() throws MojoExecutionException {
             // Store a checksum of the input spec
             File storedInputSpecHashFile = getHashFile(inputSpecFile);
             ByteSource inputSpecByteSource =
-                inputSpecFile.exists()
-                    ? Files.asByteSource(inputSpecFile)
-                    : CharSource.wrap(ClasspathHelper.loadFileFromClasspath(inputSpecFile.toString().replaceAll("\\\\","/")))
-                        .asByteSource(Charsets.UTF_8);
+                    inputSpecFile.exists()
+                            ? Files.asByteSource(inputSpecFile)
+                            : CharSource.wrap(ClasspathHelper.loadFileFromClasspath(inputSpecFile.toString().replaceAll("\\\\","/")))
+                            .asByteSource(Charsets.UTF_8);
             String  inputSpecHash =inputSpecByteSource.hash(Hashing.sha256()).toString();
 
             if (storedInputSpecHashFile.getParent() != null && !new File(storedInputSpecHashFile.getParent()).exists()) {