diff --git a/modules/openapi-generator/src/main/resources/scala-akka-http-server/multipartDirectives.mustache b/modules/openapi-generator/src/main/resources/scala-akka-http-server/multipartDirectives.mustache
index 98a2186fd2e7bcd372a83db5d4e9d45758f1512f..6e802204c57d2c2b62eb53113c649688193cb70a 100644
--- a/modules/openapi-generator/src/main/resources/scala-akka-http-server/multipartDirectives.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-akka-http-server/multipartDirectives.mustache
@@ -1,6 +1,7 @@
 package {{invokerPackage}}
 
 import java.io.File
+import java.nio.file.Files
 
 import akka.annotation.ApiMayChange
 import akka.http.scaladsl.model.Multipart.FormData
@@ -69,7 +70,7 @@ trait MultipartDirectives {
 
 object MultipartDirectives extends MultipartDirectives with FileUploadDirectives {
   val tempFileFromFileInfo: FileInfo => File = {
-    file: FileInfo => File.createTempFile(file.fileName, ".tmp")
+    file: FileInfo => Files.createTempFile(file.fileName, ".tmp").toFile()
   }
 }
 
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/ApiClient.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/ApiClient.mustache
index 116f14c8650372d8485bb1cbc024580a196c2f9e..d75e455961c52d3a12e20e211f8ea35e393012d5 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/ApiClient.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/ApiClient.mustache
@@ -1,28 +1,38 @@
-//overloaded main template file to add this comment
-
 {{>licenseInfo}}
 package {{invokerPackage}};
 
+{{#threetenbp}}
+import org.threeten.bp.*;
+
+{{/threetenbp}}
 import com.fasterxml.jackson.annotation.*;
 import com.fasterxml.jackson.databind.*;
+{{#joda}}
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+{{/joda}}
 {{#java8}}
-import com.fasterxml.jackson.datatype.jsr310.*;
-{{/java8}}
-{{^java8}}
-import com.fasterxml.jackson.datatype.joda.*;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+{{^threetenbp}}
+import java.time.OffsetDateTime;
+{{/threetenbp}}
 {{/java8}}
+{{#threetenbp}}
+import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule;
+{{/threetenbp}}
 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
 
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.GenericType;
 import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.api.client.filter.GZIPContentEncodingFilter;
 import com.sun.jersey.api.client.filter.LoggingFilter;
 import com.sun.jersey.api.client.WebResource.Builder;
 
 import com.sun.jersey.multipart.FormDataMultiPart;
 import com.sun.jersey.multipart.file.FileDataBodyPart;
 
+import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.Response.Status.Family;
 import javax.ws.rs.core.MediaType;
 
@@ -31,7 +41,9 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.TimeZone;
@@ -44,14 +56,51 @@ import java.io.UnsupportedEncodingException;
 import java.text.DateFormat;
 
 import {{invokerPackage}}.auth.Authentication;
+{{#hasHttpBasicMethods}}
 import {{invokerPackage}}.auth.HttpBasicAuth;
+{{/hasHttpBasicMethods}}
+{{#hasHttpBearerMethods}}
+import {{invokerPackage}}.auth.HttpBearerAuth;
+{{/hasHttpBearerMethods}}
+{{#hasApiKeyMethods}}
 import {{invokerPackage}}.auth.ApiKeyAuth;
+{{/hasApiKeyMethods}}
+{{#hasOAuthMethods}}
 import {{invokerPackage}}.auth.OAuth;
+{{/hasOAuthMethods}}
 
 {{>generatedAnnotation}}
-public class ApiClient {
+public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
   private Map<String, String> defaultHeaderMap = new HashMap<String, String>();
-  private String basePath = "{{basePath}}";
+  private Map<String, String> defaultCookieMap = new HashMap<String, String>();
+  private String basePath = "{{{basePath}}}";
+  protected List<ServerConfiguration> servers = new ArrayList<ServerConfiguration>({{#servers}}{{#-first}}Arrays.asList(
+{{/-first}}    new ServerConfiguration(
+      "{{{url}}}",
+      "{{{description}}}{{^description}}No description provided{{/description}}",
+      new HashMap<String, ServerVariable>(){{#variables}}{{#-first}} {{
+{{/-first}}        put("{{{name}}}", new ServerVariable(
+          "{{{description}}}{{^description}}No description provided{{/description}}",
+          "{{{defaultValue}}}",
+          new HashSet<String>(
+          {{#enumValues}}
+          {{#-first}}
+            Arrays.asList(
+          {{/-first}}
+              "{{{.}}}"{{^-last}},{{/-last}}
+          {{#-last}}
+            )
+          {{/-last}}
+          {{/enumValues}}
+          )
+        ));
+      {{#-last}}
+      }}{{/-last}}{{/variables}}
+    ){{^-last}},{{/-last}}
+  {{#-last}}
+  ){{/-last}}{{/servers}});
+  protected Integer serverIndex = 0;
+  protected Map<String, String> serverVariables = null;
   private boolean debugging = false;
   private int connectionTimeout = 0;
 
@@ -69,15 +118,23 @@ public class ApiClient {
     objectMapper = new ObjectMapper();
     objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
     objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
     objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
     objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
     objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+    {{#joda}}
+    objectMapper.registerModule(new JodaModule());
+    {{/joda}}
     {{#java8}}
     objectMapper.registerModule(new JavaTimeModule());
     {{/java8}}
-    {{^java8}}
-    objectMapper.registerModule(new JodaModule());
-    {{/java8}}
+    {{#threetenbp}}
+    ThreeTenModule module = new ThreeTenModule();
+    module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT);
+    module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME);
+    module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME);
+    objectMapper.registerModule(module);
+    {{/threetenbp}}
     objectMapper.setDateFormat(ApiClient.buildDefaultDateFormat());
 
     dateFormat = ApiClient.buildDefaultDateFormat();
@@ -86,8 +143,9 @@ public class ApiClient {
     setUserAgent("{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{{artifactVersion}}}/java{{/httpUserAgent}}");
 
     // Setup authentications (key: authentication name, value: authentication).
-    authentications = new HashMap<String, Authentication>();{{#authMethods}}{{#isBasic}}
-    authentications.put("{{name}}", new HttpBasicAuth());{{/isBasic}}{{#isApiKey}}
+    authentications = new HashMap<String, Authentication>();{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
+    authentications.put("{{name}}", new HttpBasicAuth());{{/isBasicBasic}}{{^isBasicBasic}}
+    authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));{{/isBasicBasic}}{{/isBasic}}{{#isApiKey}}
     authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}}
     authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}
     // Prevent the authentications from being modified.
@@ -112,6 +170,7 @@ public class ApiClient {
     DefaultClientConfig conf = new DefaultClientConfig();
     conf.getSingletons().add(jsonProvider);
     Client client = Client.create(conf);
+    client.addFilter(new GZIPContentEncodingFilter({{#useGzipFeature}}true{{/useGzipFeature}}{{^useGzipFeature}}false{{/useGzipFeature}}));
     if (debugging) {
       client.addFilter(new LoggingFilter());
     }
@@ -156,6 +215,33 @@ public class ApiClient {
     return this;
   }
 
+  public List<ServerConfiguration> getServers() {
+    return servers;
+  }
+
+  public ApiClient setServers(List<ServerConfiguration> servers) {
+    this.servers = servers;
+    return this;
+  }
+
+  public Integer getServerIndex() {
+    return serverIndex;
+  }
+
+  public ApiClient setServerIndex(Integer serverIndex) {
+    this.serverIndex = serverIndex;
+    return this;
+  }
+
+  public Map<String, String> getServerVariables() {
+    return serverVariables;
+  }
+
+  public ApiClient setServerVariables(Map<String, String> serverVariables) {
+    this.serverVariables = serverVariables;
+    return this;
+  }
+
   /**
    * Gets the status code of the previous request
    * @return Status code
@@ -190,6 +276,24 @@ public class ApiClient {
     return authentications.get(authName);
   }
 
+  {{#hasHttpBearerMethods}}
+  /**
+   * Helper method to set access token for the first Bearer authentication.
+   * @param bearerToken Bearer token
+   */
+  public void setBearerToken(String bearerToken) {
+    for (Authentication auth : authentications.values()) {
+      if (auth instanceof HttpBearerAuth) {
+        ((HttpBearerAuth) auth).setBearerToken(bearerToken);
+        return;
+      }
+    }
+    throw new RuntimeException("No Bearer authentication configured!");
+  }
+
+  {{/hasHttpBearerMethods}}
+
+  {{#hasHttpBasicMethods}}
   /**
    * Helper method to set username for the first HTTP basic authentication.
    * @param username Username
@@ -218,9 +322,12 @@ public class ApiClient {
     throw new RuntimeException("No HTTP basic authentication configured!");
   }
 
+  {{/hasHttpBasicMethods}}
+
+  {{#hasApiKeyMethods}}
   /**
    * Helper method to set API key value for the first API key authentication.
-   * @param apiKey API key
+   * @param apiKey the API key
    */
   public void setApiKey(String apiKey) {
     for (Authentication auth : authentications.values()) {
@@ -246,6 +353,9 @@ public class ApiClient {
     throw new RuntimeException("No API key authentication configured!");
   }
 
+  {{/hasApiKeyMethods}}
+
+  {{#hasOAuthMethods}}
   /**
    * Helper method to set access token for the first OAuth2 authentication.
    * @param accessToken Access token
@@ -260,6 +370,8 @@ public class ApiClient {
     throw new RuntimeException("No OAuth2 authentication configured!");
   }
 
+  {{/hasOAuthMethods}}
+
   /**
    * Set the User-Agent header's value (by adding to the default header map).
    * @param userAgent User agent
@@ -282,6 +394,18 @@ public class ApiClient {
     return this;
   }
 
+  /**
+   * Add a default cookie.
+   *
+   * @param key The cookie's key
+   * @param value The cookie's value
+   * @return API client
+   */
+  public ApiClient addDefaultCookie(String key, String value) {
+    defaultCookieMap.put(key, value);
+    return this;
+  }
+
   /**
    * Check that whether debugging is enabled for this API client.
    * @return True if debugging is on
@@ -378,7 +502,9 @@ public class ApiClient {
       return "";
     } else if (param instanceof Date) {
       return formatDate((Date) param);
-    } else if (param instanceof Collection) {
+    } {{#jsr310}}else if (param instanceof OffsetDateTime) {
+      return formatOffsetDateTime((OffsetDateTime) param);
+    } {{/jsr310}}else if (param instanceof Collection) {
       StringBuilder b = new StringBuilder();
       for(Object o : (Collection<?>)param) {
         if(b.length() > 0) {
@@ -392,62 +518,71 @@ public class ApiClient {
     }
   }
 
-  /*
-   * Format to {@code Pair} objects.
-   * @param collectionFormat Collection format
-   * @param name Name
-   * @param value Value
-   * @return List of pair
+  /**
+   * Formats the specified query parameter to a list containing a single {@code Pair} object.
+   *
+   * Note that {@code value} must not be a collection.
+   *
+   * @param name The name of the parameter.
+   * @param value The value of the parameter.
+   * @return A list containing a single {@code Pair} object.
    */
-  public List<Pair> parameterToPairs(String collectionFormat, String name, Object value){
+  public List<Pair> parameterToPair(String name, Object value) {
     List<Pair> params = new ArrayList<Pair>();
 
     // preconditions
-    if (name == null || name.isEmpty() || value == null) return params;
+    if (name == null || name.isEmpty() || value == null || value instanceof Collection) return params;
 
-    Collection<?> valueCollection;
-    if (value instanceof Collection<?>) {
-      valueCollection = (Collection<?>) value;
-    } else {
-      params.add(new Pair(name, parameterToString(value)));
-      return params;
-    }
+    params.add(new Pair(name, parameterToString(value)));
+    return params;
+  }
+
+  /**
+   * Formats the specified collection query parameters to a list of {@code Pair} objects.
+   *
+   * Note that the values of each of the returned Pair objects are percent-encoded.
+   *
+   * @param collectionFormat The collection format of the parameter.
+   * @param name The name of the parameter.
+   * @param value The value of the parameter.
+   * @return A list of {@code Pair} objects.
+   */
+  public List<Pair> parameterToPairs(String collectionFormat, String name, Collection value) {
+    List<Pair> params = new ArrayList<Pair>();
 
-    if (valueCollection.isEmpty()){
+    // preconditions
+    if (name == null || name.isEmpty() || value == null) {
       return params;
     }
 
-    // get the collection format
-    String format = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat); // default: csv
-
     // create the params based on the collection format
-    if ("multi".equals(format)) {
-      for (Object item : valueCollection) {
-        params.add(new Pair(name, parameterToString(item)));
+    if ("multi".equals(collectionFormat)) {
+      for (Object item : value) {
+        params.add(new Pair(name, escapeString(parameterToString(item))));
       }
-
       return params;
     }
 
+    // collectionFormat is assumed to be "csv" by default
     String delimiter = ",";
 
-    if ("csv".equals(format)) {
-      delimiter = ",";
-    } else if ("ssv".equals(format)) {
-      delimiter = " ";
-    } else if ("tsv".equals(format)) {
-      delimiter = "\t";
-    } else if ("pipes".equals(format)) {
-      delimiter = "|";
+    // escape all delimiters except commas, which are URI reserved
+    // characters
+    if ("ssv".equals(collectionFormat)) {
+      delimiter = escapeString(" ");
+    } else if ("tsv".equals(collectionFormat)) {
+      delimiter = escapeString("\t");
+    } else if ("pipes".equals(collectionFormat)) {
+      delimiter = escapeString("|");
     }
 
     StringBuilder sb = new StringBuilder() ;
-    for (Object item : valueCollection) {
+    for (Object item : value) {
       sb.append(delimiter);
-      sb.append(parameterToString(item));
+      sb.append(escapeString(parameterToString(item)));
     }
 
-    params.add(new Pair(name, sb.substring(1)));
+    params.add(new Pair(name, sb.substring(delimiter.length())));
 
     return params;
   }
@@ -458,11 +593,13 @@ public class ApiClient {
    *   application/json
    *   application/json; charset=UTF8
    *   APPLICATION/JSON
+   *   application/vnd.company+json
    * @param mime MIME
    * @return True if MIME type is boolean
    */
   public boolean isJsonMime(String mime) {
-    return mime != null && mime.matches("(?i)application\\/json(;.*)?");
+    String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$";
+    return mime != null && (mime.matches(jsonMime) || mime.equals("*/*"));
   }
 
   /**
@@ -493,10 +630,10 @@ public class ApiClient {
    *
    * @param contentTypes The Content-Type array to select from
    * @return The Content-Type header to use. If the given array is empty,
-   *   JSON will be used.
+   *   or matches "any", JSON will be used.
    */
   public String selectHeaderContentType(String[] contentTypes) {
-    if (contentTypes.length == 0) {
+    if (contentTypes.length == 0 || contentTypes[0].equals("*/*")) {
       return "application/json";
     }
     for (String contentType : contentTypes) {
@@ -561,11 +698,24 @@ public class ApiClient {
    *
    * @param path The sub path
    * @param queryParams The query parameters
+   * @param collectionQueryParams The collection query parameters
    * @return The full URL
    */
-  private String buildUrl(String path, List<Pair> queryParams) {
+  private String buildUrl(String path, List<Pair> queryParams, List<Pair> collectionQueryParams) {
+    String baseURL;
+    if (serverIndex != null) {
+      if (serverIndex < 0 || serverIndex >= servers.size()) {
+        throw new ArrayIndexOutOfBoundsException(String.format(
+          "Invalid index %d when selecting the host settings. Must be less than %d", serverIndex, servers.size()
+        ));
+      }
+      baseURL = servers.get(serverIndex).URL(serverVariables);
+    } else {
+      baseURL = basePath;
+    }
+
     final StringBuilder url = new StringBuilder();
-    url.append(basePath).append(path);
+    url.append(baseURL).append(path);
 
     if (queryParams != null && !queryParams.isEmpty()) {
       // support (constant) query string in `path`, e.g. "/posts?draft=1"
@@ -584,17 +734,34 @@ public class ApiClient {
       }
     }
 
+    if (collectionQueryParams != null && !collectionQueryParams.isEmpty()) {
+      String prefix = url.toString().contains("?") ? "&" : "?";
+      for (Pair param : collectionQueryParams) {
+        if (param.getValue() != null) {
+          if (prefix != null) {
+            url.append(prefix);
+            prefix = null;
+          } else {
+            url.append("&");
+          }
+          String value = parameterToString(param.getValue());
+          // collection query parameter value already escaped as part of parameterToPairs
+          url.append(escapeString(param.getName())).append("=").append(value);
+        }
+      }
+    }
+
     return url.toString();
   }
 
-  private ClientResponse getAPIResponse(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames) throws ApiException {
+  private ClientResponse getAPIResponse(String path, String method, List<Pair> queryParams, List<Pair> collectionQueryParams, Object body, Map<String, String> headerParams, Map<String, String> cookieParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames) throws ApiException {
     if (body != null && !formParams.isEmpty()) {
       throw new ApiException(500, "Cannot have body and form params");
     }
 
-    updateParamsForAuth(authNames, queryParams, headerParams);
+    updateParamsForAuth(authNames, queryParams, headerParams, cookieParams);
 
-    final String url = buildUrl(path, queryParams);
+    final String url = buildUrl(path, queryParams, collectionQueryParams);
     Builder builder;
     if (accept == null) {
       builder = httpClient.resource(url).getRequestBuilder();
@@ -602,12 +769,21 @@ public class ApiClient {
       builder = httpClient.resource(url).accept(accept);
     }
 
-    for (String key : headerParams.keySet()) {
-      builder = builder.header(key, headerParams.get(key));
+    for (Entry<String, String> keyValue : headerParams.entrySet()) {
+      builder = builder.header(keyValue.getKey(), keyValue.getValue());
     }
-    for (String key : defaultHeaderMap.keySet()) {
-      if (!headerParams.containsKey(key)) {
-        builder = builder.header(key, defaultHeaderMap.get(key));
+    for (Map.Entry<String,String> keyValue : defaultHeaderMap.entrySet()) {
+      if (!headerParams.containsKey(keyValue.getKey())) {
+        builder = builder.header(keyValue.getKey(), keyValue.getValue());
+      }
+    }
+
+    for (Entry<String, String> keyValue : cookieParams.entrySet()) {
+      builder = builder.cookie(new Cookie(keyValue.getKey(), keyValue.getValue()));
+    }
+    for (Map.Entry<String,String> keyValue : defaultCookieMap.entrySet()) {
+      if (!cookieParams.containsKey(keyValue.getKey())) {
+        builder = builder.cookie(new Cookie(keyValue.getKey(), keyValue.getValue()));
       }
     }
 
@@ -623,8 +799,9 @@ public class ApiClient {
       response = builder.type(contentType).delete(ClientResponse.class, serialize(body, contentType, formParams));
     } else if ("PATCH".equals(method)) {
       response = builder.type(contentType).header("X-HTTP-Method-Override", "PATCH").post(ClientResponse.class, serialize(body, contentType, formParams));
-    }
-    else {
+    } else if ("HEAD".equals(method)) {
+      response = builder.head();
+    } else {
       throw new ApiException(500, "unknown method type " + method);
     }
     return response;
@@ -637,8 +814,10 @@ public class ApiClient {
    * @param path The sub-path of the HTTP URL
    * @param method The request method, one of "GET", "POST", "PUT", and "DELETE"
    * @param queryParams The query parameters
+   * @param collectionQueryParams The collection query parameters
    * @param body The request body object - if it is not binary, otherwise null
    * @param headerParams The header parameters
+   * @param cookieParams The cookie parameters
    * @param formParams The form parameters
    * @param accept The request's Accept header
    * @param contentType The request's Content-Type header
@@ -647,9 +826,9 @@ public class ApiClient {
    * @return The response body in type of string
    * @throws ApiException API exception
    */
-   public <T> T invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType) throws ApiException {
+   public <T> T invokeAPI(String path, String method, List<Pair> queryParams, List<Pair> collectionQueryParams, Object body, Map<String, String> headerParams, Map<String, String> cookieParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType) throws ApiException {
 
-    ClientResponse response = getAPIResponse(path, method, queryParams, body, headerParams, formParams, accept, contentType, authNames);
+    ClientResponse response = getAPIResponse(path, method, queryParams, collectionQueryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames);
 
     statusCode = response.getStatusInfo().getStatusCode();
     responseHeaders = response.getHeaders();
@@ -686,12 +865,13 @@ public class ApiClient {
    * @param authNames The authentications to apply
    * @param queryParams Query parameters
    * @param headerParams Header parameters
+   * @param cookieParams Cookie parameters
    */
-  private void updateParamsForAuth(String[] authNames, List<Pair> queryParams, Map<String, String> headerParams) {
+  private void updateParamsForAuth(String[] authNames, List<Pair> queryParams, Map<String, String> headerParams, Map<String, String> cookieParams) {
     for (String authName : authNames) {
       Authentication auth = authentications.get(authName);
       if (auth == null) throw new RuntimeException("Authentication undefined: " + authName);
-      auth.applyToParams(queryParams, headerParams);
+      auth.applyToParams(queryParams, headerParams, cookieParams);
     }
   }
 
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/ApiClient.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/ApiClient.mustache
index 52c3c06e24cccdaae8654cd5ec2f2c5b8b5def89..65494e8ea04a64449ce712d1c994b22ff71d06b2 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/ApiClient.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/ApiClient.mustache
@@ -1,5 +1,3 @@
-//overloaded template file within library folder to add this comment
-
 package {{invokerPackage}};
 
 import javax.ws.rs.client.Client;
@@ -13,9 +11,12 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+{{#hasOAuthMethods}}
+import com.github.scribejava.core.model.OAuth2AccessToken;
+{{/hasOAuthMethods}}
 import org.glassfish.jersey.client.ClientConfig;
 import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.filter.LoggingFilter;
+import org.glassfish.jersey.client.HttpUrlConnectorProvider;
 import org.glassfish.jersey.jackson.JacksonFeature;
 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
@@ -25,22 +26,38 @@ import org.glassfish.jersey.media.multipart.MultiPartFeature;
 import java.io.IOException;
 import java.io.InputStream;
 
-{{^supportJava6}}
+import java.net.URI;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.X509Certificate;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
-{{/supportJava6}}
-{{#supportJava6}}
-import org.apache.commons.io.FileUtils;
-{{/supportJava6}}
+import org.glassfish.jersey.logging.LoggingFeature;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.TimeZone;
+{{#jsr310}}
+{{#threetenbp}}
+import org.threeten.bp.OffsetDateTime;
+{{/threetenbp}}
+{{^threetenbp}}
+import java.time.OffsetDateTime;
+{{/threetenbp}}
+{{/jsr310}}
 
 import java.net.URLEncoder;
 
@@ -53,30 +70,120 @@ import java.util.regex.Pattern;
 
 import {{invokerPackage}}.auth.Authentication;
 import {{invokerPackage}}.auth.HttpBasicAuth;
+import {{invokerPackage}}.auth.HttpBearerAuth;
+{{#hasHttpSignatureMethods}}
+import {{invokerPackage}}.auth.HttpSignatureAuth;
+{{/hasHttpSignatureMethods}}
 import {{invokerPackage}}.auth.ApiKeyAuth;
+{{#hasOAuthMethods}}
 import {{invokerPackage}}.auth.OAuth;
+{{/hasOAuthMethods}}
 
 {{>generatedAnnotation}}
-public class ApiClient {
-  private Map<String, String> defaultHeaderMap = new HashMap<String, String>();
-  private String basePath = "{{{basePath}}}";
-  private boolean debugging = false;
-  private int connectionTimeout = 0;
-
-  private Client httpClient;
-  private JSON json;
-  private String tempFolderPath = null;
-
-  private Map<String, Authentication> authentications;
-
-  private int statusCode;
-  private Map<String, List<String>> responseHeaders;
-
-  private DateFormat dateFormat;
+public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
+  protected Map<String, String> defaultHeaderMap = new HashMap<String, String>();
+  protected Map<String, String> defaultCookieMap = new HashMap<String, String>();
+  protected String basePath = "{{{basePath}}}";
+  protected String userAgent;
+  private static final Logger log = Logger.getLogger(ApiClient.class.getName());
+
+  protected List<ServerConfiguration> servers = new ArrayList<ServerConfiguration>({{#servers}}{{#-first}}Arrays.asList(
+{{/-first}}    new ServerConfiguration(
+      "{{{url}}}",
+      "{{{description}}}{{^description}}No description provided{{/description}}",
+      new HashMap<String, ServerVariable>(){{#variables}}{{#-first}} {{
+{{/-first}}        put("{{{name}}}", new ServerVariable(
+          "{{{description}}}{{^description}}No description provided{{/description}}",
+          "{{{defaultValue}}}",
+          new HashSet<String>(
+          {{#enumValues}}
+          {{#-first}}
+            Arrays.asList(
+          {{/-first}}
+              "{{{.}}}"{{^-last}},{{/-last}}
+          {{#-last}}
+            )
+          {{/-last}}
+          {{/enumValues}}
+          )
+        ));
+      {{#-last}}
+      }}{{/-last}}{{/variables}}
+    ){{^-last}},{{/-last}}
+  {{#-last}}
+  ){{/-last}}{{/servers}});
+  protected Integer serverIndex = 0;
+  protected Map<String, String> serverVariables = null;
+  protected Map<String, List<ServerConfiguration>> operationServers = new HashMap<String, List<ServerConfiguration>>() {{
+    {{#apiInfo}}
+    {{#apis}}
+    {{#operations}}
+    {{#operation}}
+    {{#servers}}
+    {{#-first}}
+    put("{{{classname}}}.{{{operationId}}}", new ArrayList<ServerConfiguration>(Arrays.asList(
+    {{/-first}}
+      new ServerConfiguration(
+        "{{{url}}}",
+        "{{{description}}}{{^description}}No description provided{{/description}}",
+        new HashMap<String, ServerVariable>(){{#variables}}{{#-first}} {{
+{{/-first}}          put("{{{name}}}", new ServerVariable(
+            "{{{description}}}{{^description}}No description provided{{/description}}",
+            "{{{defaultValue}}}",
+            new HashSet<String>(
+            {{#enumValues}}
+            {{#-first}}
+              Arrays.asList(
+            {{/-first}}
+                "{{{.}}}"{{^-last}},{{/-last}}
+            {{#-last}}
+              )
+            {{/-last}}
+            {{/enumValues}}
+            )
+          ));
+        {{#-last}}
+        }}{{/-last}}{{/variables}}
+      ){{^-last}},{{/-last}}
+    {{#-last}}
+    )));{{/-last}}
+    {{/servers}}
+    {{/operation}}
+    {{/operations}}
+    {{/apis}}
+    {{/apiInfo}}
+  }};
+  protected Map<String, Integer> operationServerIndex = new HashMap<String, Integer>();
+  protected Map<String, Map<String, String>> operationServerVariables = new HashMap<String, Map<String, String>>();
+  protected boolean debugging = false;
+  protected ClientConfig clientConfig;
+  protected int connectionTimeout = 0;
+  private int readTimeout = 0;
+
+  protected Client httpClient;
+  protected JSON json;
+  protected String tempFolderPath = null;
+
+  protected Map<String, Authentication> authentications;
+  protected Map<String, String> authenticationLookup;
+
+  protected DateFormat dateFormat;
 
+  /**
+   * Constructs a new ApiClient with default parameters.
+   */
   public ApiClient() {
+    this(null);
+  }
+
+  /**
+   * Constructs a new ApiClient with the specified authentication parameters.
+   *
+   * @param authMap A hash map containing authentication parameters.
+   */
+  public ApiClient(Map<String, Authentication> authMap) {
     json = new JSON();
-    httpClient = buildHttpClient(debugging);
+    httpClient = buildHttpClient();
 
     this.dateFormat = new RFC3339DateFormat();
 
@@ -84,16 +191,59 @@ public class ApiClient {
     setUserAgent("{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{{artifactVersion}}}/java{{/httpUserAgent}}");
 
     // Setup authentications (key: authentication name, value: authentication).
-    authentications = new HashMap<String, Authentication>();{{#authMethods}}{{#isBasic}}
-    authentications.put("{{name}}", new HttpBasicAuth());{{/isBasic}}{{#isApiKey}}
-    authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}}
-    authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}
+    authentications = new HashMap<String, Authentication>();
+    Authentication auth = null;
+    {{#authMethods}}
+    if (authMap != null) {
+      auth = authMap.get("{{name}}");
+    }
+    {{#isBasic}}
+    {{#isBasicBasic}}
+    if (auth instanceof HttpBasicAuth) {
+      authentications.put("{{name}}", auth);
+    } else {
+      authentications.put("{{name}}", new HttpBasicAuth());
+    }
+    {{/isBasicBasic}}
+    {{#isBasicBearer}}
+    if (auth instanceof HttpBearerAuth) {
+      authentications.put("{{name}}", auth);
+    } else {
+      authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));
+    }
+    {{/isBasicBearer}}
+    {{#isHttpSignature}}
+    if (auth instanceof HttpSignatureAuth) {
+      authentications.put("{{name}}", auth);
+    }
+    {{/isHttpSignature}}
+    {{/isBasic}}
+    {{#isApiKey}}
+    if (auth instanceof ApiKeyAuth) {
+      authentications.put("{{name}}", auth);
+    } else {
+      authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));
+    }
+    {{/isApiKey}}
+    {{#isOAuth}}
+    if (auth instanceof OAuth) {
+      authentications.put("{{name}}", auth);
+    } else {
+      authentications.put("{{name}}", new OAuth(basePath, "{{tokenUrl}}"));
+    }
+    {{/isOAuth}}
+    {{/authMethods}}
     // Prevent the authentications from being modified.
     authentications = Collections.unmodifiableMap(authentications);
+
+    // Setup authentication lookup (key: authentication alias, value: authentication name)
+    authenticationLookup = new HashMap<String, String>();{{#authMethods}}{{#vendorExtensions.x-auth-id-alias}}
+    authenticationLookup.put("{{name}}", "{{.}}");{{/vendorExtensions.x-auth-id-alias}}{{/authMethods}}
   }
 
   /**
    * Gets the JSON instance to do JSON serialization and deserialization.
+   *
    * @return JSON
    */
   public JSON getJSON() {
@@ -109,33 +259,77 @@ public class ApiClient {
     return this;
   }
 
+  /**
+   * Returns the base URL to the location where the OpenAPI document is being served.
+   *
+   * @return The base URL to the target host.
+   */
   public String getBasePath() {
     return basePath;
   }
 
+  /**
+   * Sets the base URL to the location where the OpenAPI document is being served.
+   *
+   * @param basePath The base URL to the target host.
+   */
   public ApiClient setBasePath(String basePath) {
     this.basePath = basePath;
+    {{#hasOAuthMethods}}
+    setOauthBasePath(basePath);
+    {{/hasOAuthMethods}}
     return this;
   }
 
-  /**
-   * Gets the status code of the previous request
-   * @return Status code
-   */
-  public int getStatusCode() {
-    return statusCode;
+  public List<ServerConfiguration> getServers() {
+    return servers;
   }
 
-  /**
-   * Gets the response headers of the previous request
-   * @return Response headers
-   */
-  public Map<String, List<String>> getResponseHeaders() {
-    return responseHeaders;
+  public ApiClient setServers(List<ServerConfiguration> servers) {
+    this.servers = servers;
+    updateBasePath();
+    return this;
+  }
+
+  public Integer getServerIndex() {
+    return serverIndex;
+  }
+
+  public ApiClient setServerIndex(Integer serverIndex) {
+    this.serverIndex = serverIndex;
+    updateBasePath();
+    return this;
+  }
+
+  public Map<String, String> getServerVariables() {
+    return serverVariables;
+  }
+
+  public ApiClient setServerVariables(Map<String, String> serverVariables) {
+    this.serverVariables = serverVariables;
+    updateBasePath();
+    return this;
+  }
+
+  private void updateBasePath() {
+    if (serverIndex != null) {
+        setBasePath(servers.get(serverIndex).URL(serverVariables));
+    }
   }
 
+  {{#hasOAuthMethods}}
+  private void setOauthBasePath(String basePath) {
+    for(Authentication auth : authentications.values()) {
+      if (auth instanceof OAuth) {
+        ((OAuth) auth).setBasePath(basePath);
+      }
+    }
+  }
+
+  {{/hasOAuthMethods}}
   /**
    * Get authentications (key: authentication name, value: authentication).
+   *
    * @return Map of authentication object
    */
   public Map<String, Authentication> getAuthentications() {
@@ -154,13 +348,14 @@ public class ApiClient {
 
   /**
    * Helper method to set username for the first HTTP basic authentication.
+   *
    * @param username Username
    */
-  public void setUsername(String username) {
+  public ApiClient setUsername(String username) {
     for (Authentication auth : authentications.values()) {
       if (auth instanceof HttpBasicAuth) {
         ((HttpBasicAuth) auth).setUsername(username);
-        return;
+        return this;
       }
     }
     throw new RuntimeException("No HTTP basic authentication configured!");
@@ -168,13 +363,14 @@ public class ApiClient {
 
   /**
    * Helper method to set password for the first HTTP basic authentication.
+   *
    * @param password Password
    */
-  public void setPassword(String password) {
+  public ApiClient setPassword(String password) {
     for (Authentication auth : authentications.values()) {
       if (auth instanceof HttpBasicAuth) {
         ((HttpBasicAuth) auth).setPassword(password);
-        return;
+        return this;
       }
     }
     throw new RuntimeException("No HTTP basic authentication configured!");
@@ -182,56 +378,167 @@ public class ApiClient {
 
   /**
    * Helper method to set API key value for the first API key authentication.
+   *
    * @param apiKey API key
    */
-  public void setApiKey(String apiKey) {
+  public ApiClient setApiKey(String apiKey) {
     for (Authentication auth : authentications.values()) {
       if (auth instanceof ApiKeyAuth) {
         ((ApiKeyAuth) auth).setApiKey(apiKey);
-        return;
+        return this;
       }
     }
     throw new RuntimeException("No API key authentication configured!");
   }
 
+  /**
+   * Helper method to configure authentications which respects aliases of API keys.
+   *
+   * @param secrets Hash map from authentication name to its secret.
+   */
+  public ApiClient configureApiKeys(Map<String, String> secrets) {
+    for (Map.Entry<String, Authentication> authEntry : authentications.entrySet()) {
+      Authentication auth = authEntry.getValue();
+      if (auth instanceof ApiKeyAuth) {
+        String name = authEntry.getKey();
+        // respect x-auth-id-alias property
+        name = authenticationLookup.containsKey(name) ? authenticationLookup.get(name) : name;
+        if (secrets.containsKey(name)) {
+          ((ApiKeyAuth) auth).setApiKey(secrets.get(name));
+        }
+      }
+    }
+    return this;
+  }
+
   /**
    * Helper method to set API key prefix for the first API key authentication.
+   *
    * @param apiKeyPrefix API key prefix
    */
-  public void setApiKeyPrefix(String apiKeyPrefix) {
+  public ApiClient setApiKeyPrefix(String apiKeyPrefix) {
     for (Authentication auth : authentications.values()) {
       if (auth instanceof ApiKeyAuth) {
         ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix);
-        return;
+        return this;
       }
     }
     throw new RuntimeException("No API key authentication configured!");
   }
 
+  /**
+   * Helper method to set bearer token for the first Bearer authentication.
+   *
+   * @param bearerToken Bearer token
+   */
+  public ApiClient setBearerToken(String bearerToken) {
+    for (Authentication auth : authentications.values()) {
+      if (auth instanceof HttpBearerAuth) {
+        ((HttpBearerAuth) auth).setBearerToken(bearerToken);
+        return this;
+      }
+    }
+    throw new RuntimeException("No Bearer authentication configured!");
+  }
+
+
+  {{#hasOAuthMethods}}
   /**
    * Helper method to set access token for the first OAuth2 authentication.
    * @param accessToken Access token
    */
-  public void setAccessToken(String accessToken) {
+  public ApiClient setAccessToken(String accessToken) {
     for (Authentication auth : authentications.values()) {
       if (auth instanceof OAuth) {
         ((OAuth) auth).setAccessToken(accessToken);
-        return;
+        return this;
       }
     }
     throw new RuntimeException("No OAuth2 authentication configured!");
   }
 
+  /**
+   * Helper method to set the credentials for the first OAuth2 authentication.
+   *
+   * @param clientId the client ID
+   * @param clientSecret the client secret
+   */
+  public ApiClient setOauthCredentials(String clientId, String clientSecret) {
+    for (Authentication auth : authentications.values()) {
+      if (auth instanceof OAuth) {
+        ((OAuth) auth).setCredentials(clientId, clientSecret, isDebugging());
+        return this;
+      }
+    }
+    throw new RuntimeException("No OAuth2 authentication configured!");
+  }
+
+  /**
+   * Helper method to set the password flow for the first OAuth2 authentication.
+   *
+   * @param username the user name
+   * @param password the user password
+   */
+  public ApiClient setOauthPasswordFlow(String username, String password) {
+    for (Authentication auth : authentications.values()) {
+      if (auth instanceof OAuth) {
+        ((OAuth) auth).usePasswordFlow(username, password);
+        return this;
+      }
+    }
+    throw new RuntimeException("No OAuth2 authentication configured!");
+  }
+
+  /**
+   * Helper method to set the authorization code flow for the first OAuth2 authentication.
+   *
+   * @param code the authorization code
+   */
+  public ApiClient setOauthAuthorizationCodeFlow(String code) {
+    for (Authentication auth : authentications.values()) {
+      if (auth instanceof OAuth) {
+        ((OAuth) auth).useAuthorizationCodeFlow(code);
+        return this;
+      }
+    }
+    throw new RuntimeException("No OAuth2 authentication configured!");
+  }
+
+  /**
+   * Helper method to set the scopes for the first OAuth2 authentication.
+   *
+   * @param scope the oauth scope
+   */
+  public ApiClient setOauthScope(String scope) {
+    for (Authentication auth : authentications.values()) {
+      if (auth instanceof OAuth) {
+        ((OAuth) auth).setScope(scope);
+        return this;
+      }
+    }
+    throw new RuntimeException("No OAuth2 authentication configured!");
+  }
+
+  {{/hasOAuthMethods}}
   /**
    * Set the User-Agent header's value (by adding to the default header map).
    * @param userAgent Http user agent
    * @return API client
    */
   public ApiClient setUserAgent(String userAgent) {
+    userAgent = userAgent;
     addDefaultHeader("User-Agent", userAgent);
     return this;
   }
 
+  /**
+   * Get the User-Agent header's value.
+   * @return User-Agent string
+   */
+  public String getUserAgent(){
+    return userAgent;
+  }
+
   /**
    * Add a default header.
    *
@@ -244,6 +551,39 @@ public class ApiClient {
     return this;
   }
 
+  /**
+   * Add a default cookie.
+   *
+   * @param key The cookie's key
+   * @param value The cookie's value
+   * @return API client
+   */
+  public ApiClient addDefaultCookie(String key, String value) {
+    defaultCookieMap.put(key, value);
+    return this;
+  }
+
+  /**
+   * Gets the client config.
+   * @return Client config
+   */
+  public ClientConfig getClientConfig() {
+    return clientConfig;
+  }
+
+  /**
+   * Set the client config.
+   *
+   * @param clientConfig Set the client config
+   * @return API client
+   */
+  public ApiClient setClientConfig(ClientConfig clientConfig) {
+    this.clientConfig = clientConfig;
+    // Rebuild HTTP Client according to the new "clientConfig" value.
+    this.httpClient = buildHttpClient();
+    return this;
+  }
+
   /**
    * Check that whether debugging is enabled for this API client.
    * @return True if debugging is switched on
@@ -261,7 +601,7 @@ public class ApiClient {
   public ApiClient setDebugging(boolean debugging) {
     this.debugging = debugging;
     // Rebuild HTTP Client according to the new "debugging" value.
-    this.httpClient = buildHttpClient(debugging);
+    this.httpClient = buildHttpClient();
     return this;
   }
 
@@ -307,6 +647,27 @@ public class ApiClient {
     return this;
   }
 
+  /**
+   * read timeout (in milliseconds).
+   * @return Read timeout
+   */
+  public int getReadTimeout() {
+    return readTimeout;
+  }
+
+  /**
+   * Set the read timeout (in milliseconds).
+   * A value of 0 means no timeout, otherwise values must be between 1 and
+   * {@link Integer#MAX_VALUE}.
+   * @param readTimeout Read timeout in milliseconds
+   * @return API client
+   */
+  public ApiClient setReadTimeout(int readTimeout) {
+    this.readTimeout = readTimeout;
+    httpClient.property(ClientProperties.READ_TIMEOUT, readTimeout);
+    return this;
+  }
+
   /**
    * Get the date format used to parse/format date parameters.
    * @return Date format
@@ -359,7 +720,9 @@ public class ApiClient {
       return "";
     } else if (param instanceof Date) {
       return formatDate((Date) param);
-    } else if (param instanceof Collection) {
+    } {{#jsr310}}else if (param instanceof OffsetDateTime) {
+      return formatOffsetDateTime((OffsetDateTime) param);
+    } {{/jsr310}}else if (param instanceof Collection) {
       StringBuilder b = new StringBuilder();
       for(Object o : (Collection)param) {
         if(b.length() > 0) {
@@ -439,11 +802,14 @@ public class ApiClient {
    *   application/json
    *   application/json; charset=UTF8
    *   APPLICATION/JSON
+   *   application/vnd.company+json
+   * "* / *" is also default to JSON
    * @param mime MIME
    * @return True if the MIME type is JSON
    */
   public boolean isJsonMime(String mime) {
-    return mime != null && mime.matches("(?i)application\\/json(;.*)?");
+    String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$";
+    return mime != null && (mime.matches(jsonMime) || mime.equals("*/*"));
   }
 
   /**
@@ -510,7 +876,7 @@ public class ApiClient {
    * @return Entity
    * @throws ApiException API exception
    */
-  public Entity<?> serialize(Object obj, Map<String, Object> formParams, String contentType) throws ApiException {
+  public Entity<?> serialize(Object obj, Map<String, Object> formParams, String contentType, boolean isBodyNullable) throws ApiException {
     Entity<?> entity;
     if (contentType.startsWith("multipart/form-data")) {
       MultiPart multiPart = new MultiPart();
@@ -534,11 +900,60 @@ public class ApiClient {
       entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE);
     } else {
       // We let jersey handle the serialization
-      entity = Entity.entity(obj, contentType);
+      if (isBodyNullable) { // payload is nullable
+        if (obj instanceof String) {
+          entity = Entity.entity(obj == null ? "null" : "\"" + ((String)obj).replaceAll("\"", Matcher.quoteReplacement("\\\"")) + "\"", contentType);
+        } else {
+          entity = Entity.entity(obj == null ? "null" : obj, contentType);
+        }
+      } else {
+        if (obj instanceof String) {
+          entity = Entity.entity(obj == null ? "" : "\"" + ((String)obj).replaceAll("\"", Matcher.quoteReplacement("\\\"")) + "\"", contentType);
+        } else {
+          entity = Entity.entity(obj == null ? "" : obj, contentType);
+        }
+      }
     }
     return entity;
   }
 
+  /**
+   * Serialize the given Java object into string according the given
+   * Content-Type (only JSON, HTTP form is supported for now).
+   * @param obj Object
+   * @param formParams Form parameters
+   * @param contentType Context type
+   * @param isBodyNullable True if the body is nullable
+   * @return String
+   * @throws ApiException API exception
+   */
+  public String serializeToString(Object obj, Map<String, Object> formParams, String contentType, boolean isBodyNullable) throws ApiException {
+    try {
+      if (contentType.startsWith("multipart/form-data")) {
+        throw new ApiException("multipart/form-data not yet supported for serializeToString (http signature authentication)");
+      } else if (contentType.startsWith("application/x-www-form-urlencoded")) {
+        String formString = "";
+        for (Entry<String, Object> param : formParams.entrySet()) {
+          formString = param.getKey() + "=" + URLEncoder.encode(parameterToString(param.getValue()), "UTF-8") + "&";
+        }
+
+        if (formString.length() == 0) { // empty string
+          return formString;
+        } else {
+          return formString.substring(0, formString.length() - 1);
+        }
+      } else {
+        if (isBodyNullable) {
+          return obj == null ? "null" : json.getMapper().writeValueAsString(obj);
+        } else {
+          return obj == null ? "" : json.getMapper().writeValueAsString(obj);
+        }
+      }
+    } catch (Exception ex) {
+      throw new ApiException("Failed to perform serializeToString: " + ex.toString());
+    }
+  }
+
   /**
    * Deserialize response body to Java object according to the Content-Type.
    * @param <T> Type
@@ -566,8 +981,9 @@ public class ApiClient {
     List<Object> contentTypes = response.getHeaders().get("Content-Type");
     if (contentTypes != null && !contentTypes.isEmpty())
       contentType = String.valueOf(contentTypes.get(0));
-    if (contentType == null)
-      throw new ApiException(500, "missing Content-Type in response");
+
+    // read the entity stream multiple times
+    response.bufferEntity();
 
     return response.readEntity(returnType);
   }
@@ -581,13 +997,7 @@ public class ApiClient {
   public File downloadFileFromResponse(Response response) throws ApiException {
     try {
       File file = prepareDownloadFile(response);
-{{^supportJava6}}
       Files.copy(response.readEntity(InputStream.class), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
-{{/supportJava6}}
-{{#supportJava6}}
-      // Java6 falls back to commons.io for file copying
-      FileUtils.copyToFile(response.readEntity(InputStream.class), file);
-{{/supportJava6}}
       return file;
     } catch (IOException e) {
       throw new ApiException(e);
@@ -618,132 +1028,286 @@ public class ApiClient {
         prefix = filename.substring(0, pos) + "-";
         suffix = filename.substring(pos);
       }
-      // File.createTempFile requires the prefix to be at least three characters long
+      // Files.createTempFile requires the prefix to be at least three characters long
       if (prefix.length() < 3)
         prefix = "download-";
     }
 
     if (tempFolderPath == null)
-      return File.createTempFile(prefix, suffix);
+      return Files.createTempFile(prefix, suffix).toFile();
     else
-      return File.createTempFile(prefix, suffix, new File(tempFolderPath));
+      return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile();
   }
 
   /**
    * Invoke API by sending HTTP request with the given options.
    *
    * @param <T> Type
+   * @param operation The qualified name of the operation
    * @param path The sub-path of the HTTP URL
-   * @param method The request method, one of "GET", "POST", "PUT", and "DELETE"
+   * @param method The request method, one of "GET", "POST", "PUT", "HEAD" and "DELETE"
    * @param queryParams The query parameters
    * @param body The request body object
    * @param headerParams The header parameters
+   * @param cookieParams The cookie parameters
    * @param formParams The form parameters
    * @param accept The request's Accept header
    * @param contentType The request's Content-Type header
    * @param authNames The authentications to apply
    * @param returnType The return type into which to deserialize the response
+   * @param isBodyNullable True if the body is nullable
    * @return The response body in type of string
    * @throws ApiException API exception
    */
-  public <T> T invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType) throws ApiException {
-    updateParamsForAuth(authNames, queryParams, headerParams);
-
-    // Not using `.target(this.basePath).path(path)` below,
+  public <T> ApiResponse<T> invokeAPI(
+      String operation,
+      String path,
+      String method,
+      List<Pair> queryParams,
+      Object body,
+      Map<String, String> headerParams,
+      Map<String, String> cookieParams,
+      Map<String, Object> formParams,
+      String accept,
+      String contentType,
+      String[] authNames,
+      GenericType<T> returnType,
+      boolean isBodyNullable)
+      throws ApiException {
+
+    // Not using `.target(targetURL).path(path)` below,
     // to support (constant) query string in `path`, e.g. "/posts?draft=1"
-    WebTarget target = httpClient.target(this.basePath + path);
+    String targetURL;
+    if (serverIndex != null && operationServers.containsKey(operation)) {
+      Integer index = operationServerIndex.containsKey(operation) ? operationServerIndex.get(operation) : serverIndex;
+      Map<String, String> variables = operationServerVariables.containsKey(operation) ?
+        operationServerVariables.get(operation) : serverVariables;
+      List<ServerConfiguration> serverConfigurations = operationServers.get(operation);
+      if (index < 0 || index >= serverConfigurations.size()) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format(
+                "Invalid index %d when selecting the host settings. Must be less than %d",
+                index, serverConfigurations.size()));
+      }
+      targetURL = serverConfigurations.get(index).URL(variables) + path;
+    } else {
+      targetURL = this.basePath + path;
+    }
+    WebTarget target = httpClient.target(targetURL);
 
     if (queryParams != null) {
       for (Pair queryParam : queryParams) {
         if (queryParam.getValue() != null) {
-          target = target.queryParam(queryParam.getName(), queryParam.getValue());
+          target = target.queryParam(queryParam.getName(), escapeString(queryParam.getValue()));
         }
       }
     }
 
     Invocation.Builder invocationBuilder = target.request().accept(accept);
 
-    for (Entry<String, String> entry : headerParams.entrySet()) {
+    for (Entry<String, String> entry : cookieParams.entrySet()) {
+      String value = entry.getValue();
+      if (value != null) {
+        invocationBuilder = invocationBuilder.cookie(entry.getKey(), value);
+      }
+    }
+
+    for (Entry<String, String> entry : defaultCookieMap.entrySet()) {
+      String value = entry.getValue();
+      if (value != null) {
+        invocationBuilder = invocationBuilder.cookie(entry.getKey(), value);
+      }
+    }
+
+    Entity<?> entity = serialize(body, formParams, contentType, isBodyNullable);
+
+    // put all headers in one place
+    Map<String, String> allHeaderParams = new HashMap<>(defaultHeaderMap);
+    allHeaderParams.putAll(headerParams);
+
+    // update different parameters (e.g. headers) for authentication
+    updateParamsForAuth(
+        authNames,
+        queryParams,
+        allHeaderParams,
+        cookieParams,
+        serializeToString(body, formParams, contentType, isBodyNullable),
+        method,
+        target.getUri());
+
+    for (Entry<String, String> entry : allHeaderParams.entrySet()) {
       String value = entry.getValue();
       if (value != null) {
         invocationBuilder = invocationBuilder.header(entry.getKey(), value);
       }
     }
 
-    for (Entry<String, String> entry : defaultHeaderMap.entrySet()) {
-      String key = entry.getKey();
-      if (!headerParams.containsKey(key)) {
-        String value = entry.getValue();
-        if (value != null) {
-          invocationBuilder = invocationBuilder.header(key, value);
+    Response response = null;
+
+    try {
+      response = sendRequest(method, invocationBuilder, entity);
+
+      {{#hasOAuthMethods}}
+      // If OAuth is used and a status 401 is received, renew the access token and retry the request
+      if (response.getStatusInfo() == Status.UNAUTHORIZED) {
+        for (String authName : authNames) {
+          Authentication authentication = authentications.get(authName);
+          if (authentication instanceof OAuth) {
+            OAuth2AccessToken accessToken = ((OAuth) authentication).renewAccessToken();
+            if (accessToken != null) {
+              invocationBuilder.header("Authorization", null);
+              invocationBuilder.header("Authorization", "Bearer " + accessToken.getAccessToken());
+              response = sendRequest(method, invocationBuilder, entity);
+            }
+            break;
+          }
         }
       }
-    }
 
-    Entity<?> entity = serialize(body, formParams, contentType);
+      {{/hasOAuthMethods}}
+      int statusCode = response.getStatusInfo().getStatusCode();
+      Map<String, List<String>> responseHeaders = buildResponseHeaders(response);
 
-    Response response;
+      if (response.getStatusInfo() == Status.NO_CONTENT) {
+        return new ApiResponse<T>(statusCode, responseHeaders);
+      } else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) {
+        if (returnType == null) {
+          return new ApiResponse<T>(statusCode, responseHeaders);
+        } else {
+          return new ApiResponse<T>(statusCode, responseHeaders, deserialize(response, returnType));
+        }
+      } else {
+        String message = "error";
+        String respBody = null;
+        if (response.hasEntity()) {
+          try {
+            respBody = String.valueOf(response.readEntity(String.class));
+            message = respBody;
+          } catch (RuntimeException e) {
+            // e.printStackTrace();
+          }
+        }
+        throw new ApiException(
+            response.getStatus(), message, buildResponseHeaders(response), respBody);
+      }
+    } finally {
+      try {
+        response.close();
+      } catch (Exception e) {
+        // it's not critical, since the response object is local in method invokeAPI; that's fine,
+        // just continue
+      }
+    }
+  }
 
-    if ("GET".equals(method)) {
-      response = invocationBuilder.get();
-    } else if ("POST".equals(method)) {
+  private Response sendRequest(String method, Invocation.Builder invocationBuilder, Entity<?> entity) {
+    Response response;
+    if ("POST".equals(method)) {
       response = invocationBuilder.post(entity);
     } else if ("PUT".equals(method)) {
       response = invocationBuilder.put(entity);
     } else if ("DELETE".equals(method)) {
-      response = invocationBuilder.delete();
+      response = invocationBuilder.method("DELETE", entity);
     } else if ("PATCH".equals(method)) {
-      response = invocationBuilder.header("X-HTTP-Method-Override", "PATCH").post(entity);
+      response = invocationBuilder.method("PATCH", entity);
     } else {
-      throw new ApiException(500, "unknown method type " + method);
+      response = invocationBuilder.method(method);
     }
+    return response;
+  }
 
-    statusCode = response.getStatusInfo().getStatusCode();
-    responseHeaders = buildResponseHeaders(response);
-
-    if (response.getStatus() == Status.NO_CONTENT.getStatusCode()) {
-      return null;
-    } else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) {
-      if (returnType == null)
-        return null;
-      else
-        return deserialize(response, returnType);
-    } else {
-      String message = "error";
-      String respBody = null;
-      if (response.hasEntity()) {
-        try {
-          respBody = String.valueOf(response.readEntity(String.class));
-          message = respBody;
-        } catch (RuntimeException e) {
-          // e.printStackTrace();
-        }
-      }
-      throw new ApiException(
-        response.getStatus(),
-        message,
-        buildResponseHeaders(response),
-        respBody);
-    }
+  /**
+   * @deprecated Add qualified name of the operation as a first parameter.
+   */
+  @Deprecated
+  public <T> ApiResponse<T> invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, String> cookieParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType, boolean isBodyNullable) throws ApiException {
+    return invokeAPI(null, path, method, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames, returnType, isBodyNullable);
   }
 
   /**
    * Build the Client used to make HTTP requests.
-   * @param debugging Debug setting
    * @return Client
    */
-  private Client buildHttpClient(boolean debugging) {
-    final ClientConfig clientConfig = new ClientConfig();
+  protected Client buildHttpClient() {
+    // recreate the client config to pickup changes
+    clientConfig = getDefaultClientConfig();
+
+    ClientBuilder clientBuilder = ClientBuilder.newBuilder();
+    customizeClientBuilder(clientBuilder);
+    clientBuilder = clientBuilder.withConfig(clientConfig);
+    return clientBuilder.build();
+  }
+
+  /**
+   * Get the default client config.
+   * @return Client config
+   */
+  public ClientConfig getDefaultClientConfig() {
+    ClientConfig clientConfig = new ClientConfig();
     clientConfig.register(MultiPartFeature.class);
     clientConfig.register(json);
     clientConfig.register(JacksonFeature.class);
+    clientConfig.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
+    // turn off compliance validation to be able to send payloads with DELETE calls
+    clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
     if (debugging) {
-      clientConfig.register(LoggingFilter.class);
+      clientConfig.register(new LoggingFeature(java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), java.util.logging.Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 1024*50 /* Log payloads up to 50K */));
+      clientConfig.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY, LoggingFeature.Verbosity.PAYLOAD_ANY);
+      // Set logger to ALL
+      java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME).setLevel(java.util.logging.Level.ALL);
+    } else {
+      // suppress warnings for payloads with DELETE calls:
+      java.util.logging.Logger.getLogger("org.glassfish.jersey.client").setLevel(java.util.logging.Level.SEVERE);
     }
-    return ClientBuilder.newClient(clientConfig);
+
+    return clientConfig;
   }
 
-  private Map<String, List<String>> buildResponseHeaders(Response response) {
+  /**
+   * Customize the client builder.
+   *
+   * This method can be overriden to customize the API client. For example, this can be used to:
+   * 1. Set the hostname verifier to be used by the client to verify the endpoint's hostname
+   *    against its identification information.
+   * 2. Set the client-side key store.
+   * 3. Set the SSL context that will be used when creating secured transport connections to
+   *    server endpoints from web targets created by the client instance that is using this SSL context.
+   * 4. Set the client-side trust store.
+   *
+   * To completely disable certificate validation (at your own risk), you can
+   * override this method and invoke disableCertificateValidation(clientBuilder).
+   */
+  protected void customizeClientBuilder(ClientBuilder clientBuilder) {
+    // No-op extension point
+  }
+
+  /**
+   * Disable X.509 certificate validation in TLS connections.
+   *
+   * Please note that trusting all certificates is extremely risky.
+   * This may be useful in a development environment with self-signed certificates.
+   */
+  protected void disableCertificateValidation(ClientBuilder clientBuilder) throws KeyManagementException, NoSuchAlgorithmException {
+    TrustManager[] trustAllCerts = new X509TrustManager[] {
+      new X509TrustManager() {
+        @Override
+        public X509Certificate[] getAcceptedIssuers() {
+          return null;
+        }
+        @Override
+        public void checkClientTrusted(X509Certificate[] certs, String authType) {
+        }
+        @Override
+        public void checkServerTrusted(X509Certificate[] certs, String authType) {
+        }
+      }
+    };
+    SSLContext sslContext = SSLContext.getInstance("TLS");
+    sslContext.init(null, trustAllCerts, new SecureRandom());
+    clientBuilder.sslContext(sslContext);
+  }
+
+  protected Map<String, List<String>> buildResponseHeaders(Response response) {
     Map<String, List<String>> responseHeaders = new HashMap<String, List<String>>();
     for (Entry<String, List<Object>> entry: response.getHeaders().entrySet()) {
       List<Object> values = entry.getValue();
@@ -760,12 +1324,20 @@ public class ApiClient {
    * Update query and header parameters based on authentication settings.
    *
    * @param authNames The authentications to apply
+   * @param queryParams List of query parameters
+   * @param headerParams Map of header parameters
+   * @param cookieParams Map of cookie parameters
+   * @param method HTTP method (e.g. POST)
+   * @param uri HTTP URI
    */
-  private void updateParamsForAuth(String[] authNames, List<Pair> queryParams, Map<String, String> headerParams) {
+  protected void updateParamsForAuth(String[] authNames, List<Pair> queryParams, Map<String, String> headerParams,
+                                     Map<String, String> cookieParams, String payload, String method, URI uri) throws ApiException {
     for (String authName : authNames) {
       Authentication auth = authentications.get(authName);
-      if (auth == null) throw new RuntimeException("Authentication undefined: " + authName);
-      auth.applyToParams(queryParams, headerParams);
+      if (auth == null) {
+        continue;
+      }
+      auth.applyToParams(queryParams, headerParams, cookieParams, payload, method, uri);
     }
   }
 }
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/JSON.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/JSON.mustache
index 52e94ec9326a16239b022b27cc1247a3340dc3de..3297c77e49b2da06da75fa3f29df7d7ba4788e5e 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/JSON.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/JSON.mustache
@@ -1,18 +1,32 @@
-//overloaded template file within library folder to add this comment
-
 package {{invokerPackage}};
 
+{{#threetenbp}}
+import org.threeten.bp.*;
+{{/threetenbp}}
 import com.fasterxml.jackson.annotation.*;
 import com.fasterxml.jackson.databind.*;
+{{#openApiNullable}}
+import org.openapitools.jackson.nullable.JsonNullableModule;
+{{/openApiNullable}}
 {{#java8}}
-import com.fasterxml.jackson.datatype.jsr310.*;
-{{/java8}}
-{{^java8}}
-import com.fasterxml.jackson.datatype.joda.*;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 {{/java8}}
+{{#joda}}
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+{{/joda}}
+{{#threetenbp}}
+import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule;
+{{/threetenbp}}
+{{#models.0}}
+import {{modelPackage}}.*;
+{{/models.0}}
 
 import java.text.DateFormat;
-
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.ws.rs.core.GenericType;
 import javax.ws.rs.ext.ContextResolver;
 
 {{>generatedAnnotation}}
@@ -22,7 +36,9 @@ public class JSON implements ContextResolver<ObjectMapper> {
   public JSON() {
     mapper = new ObjectMapper();
     mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
-    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false);
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
+    mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, true);
     mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
     mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
     mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
@@ -30,9 +46,20 @@ public class JSON implements ContextResolver<ObjectMapper> {
     {{#java8}}
     mapper.registerModule(new JavaTimeModule());
     {{/java8}}
-    {{^java8}}
+    {{#joda}}
     mapper.registerModule(new JodaModule());
-    {{/java8}}
+    {{/joda}}
+    {{#threetenbp}}
+    ThreeTenModule module = new ThreeTenModule();
+    module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT);
+    module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME);
+    module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME);
+    mapper.registerModule(module);
+    {{/threetenbp}}
+    {{#openApiNullable}}
+    JsonNullableModule jnm = new JsonNullableModule();
+    mapper.registerModule(jnm);
+    {{/openApiNullable}}
   }
 
   /**
@@ -47,4 +74,204 @@ public class JSON implements ContextResolver<ObjectMapper> {
   public ObjectMapper getContext(Class<?> type) {
     return mapper;
   }
+
+  /**
+   * Get the object mapper
+   *
+   * @return object mapper
+   */
+  public ObjectMapper getMapper() { return mapper; }
+
+  /**
+   * Returns the target model class that should be used to deserialize the input data.
+   * The discriminator mappings are used to determine the target model class.
+   *
+   * @param node The input data.
+   * @param modelClass The class that contains the discriminator mappings.
+   */
+  public static Class<?> getClassForElement(JsonNode node, Class<?> modelClass) {
+    ClassDiscriminatorMapping cdm = modelDiscriminators.get(modelClass);
+    if (cdm != null) {
+      return cdm.getClassForElement(node, new HashSet<Class<?>>());
+    }
+    return null;
+  }
+
+  /**
+   * Helper class to register the discriminator mappings.
+   */
+  private static class ClassDiscriminatorMapping {
+    // The model class name.
+    Class<?> modelClass;
+    // The name of the discriminator property.
+    String discriminatorName;
+    // The discriminator mappings for a model class.
+    Map<String, Class<?>> discriminatorMappings;
+
+    // Constructs a new class discriminator.
+    ClassDiscriminatorMapping(Class<?> cls, String propertyName, Map<String, Class<?>> mappings) {
+      modelClass = cls;
+      discriminatorName = propertyName;
+      discriminatorMappings = new HashMap<String, Class<?>>();
+      if (mappings != null) {
+        discriminatorMappings.putAll(mappings);
+      }
+    }
+
+    // Return the name of the discriminator property for this model class.
+    String getDiscriminatorPropertyName() {
+      return discriminatorName;
+    }
+
+    // Return the discriminator value or null if the discriminator is not
+    // present in the payload.
+    String getDiscriminatorValue(JsonNode node) {
+      // Determine the value of the discriminator property in the input data.
+      if (discriminatorName != null) {
+        // Get the value of the discriminator property, if present in the input payload.
+        node = node.get(discriminatorName);
+        if (node != null && node.isValueNode()) {
+          String discrValue = node.asText();
+          if (discrValue != null) {
+            return discrValue;
+          }
+        }
+      }
+      return null;
+    }
+
+    /**
+     * Returns the target model class that should be used to deserialize the input data.
+     * This function can be invoked for anyOf/oneOf composed models with discriminator mappings.
+     * The discriminator mappings are used to determine the target model class.
+     *
+     * @param node The input data.
+     * @param visitedClasses The set of classes that have already been visited.
+     */
+    Class<?> getClassForElement(JsonNode node, Set<Class<?>> visitedClasses) {
+      if (visitedClasses.contains(modelClass)) {
+        // Class has already been visited.
+        return null;
+      }
+      // Determine the value of the discriminator property in the input data.
+      String discrValue = getDiscriminatorValue(node);
+      if (discrValue == null) {
+        return null;
+      }
+      Class<?> cls = discriminatorMappings.get(discrValue);
+      // It may not be sufficient to return this cls directly because that target class
+      // may itself be a composed schema, possibly with its own discriminator.
+      visitedClasses.add(modelClass);
+      for (Class<?> childClass : discriminatorMappings.values()) {
+        ClassDiscriminatorMapping childCdm = modelDiscriminators.get(childClass);
+        if (childCdm == null) {
+          continue;
+        }
+        if (!discriminatorName.equals(childCdm.discriminatorName)) {
+          discrValue = getDiscriminatorValue(node);
+          if (discrValue == null) {
+            continue;
+          }
+        }
+        if (childCdm != null) {
+          // Recursively traverse the discriminator mappings.
+          Class<?> childDiscr = childCdm.getClassForElement(node, visitedClasses);
+          if (childDiscr != null) {
+            return childDiscr;
+          }
+        }
+      }
+      return cls;
+    }
+  }
+
+  /**
+   * Returns true if inst is an instance of modelClass in the OpenAPI model hierarchy.
+   *
+   * The Java class hierarchy is not implemented the same way as the OpenAPI model hierarchy,
+   * so it's not possible to use the instanceof keyword.
+   *
+   * @param modelClass A OpenAPI model class.
+   * @param inst The instance object.
+   */
+  public static boolean isInstanceOf(Class<?> modelClass, Object inst, Set<Class<?>> visitedClasses) {
+    if (modelClass.isInstance(inst)) {
+      // This handles the 'allOf' use case with single parent inheritance.
+      return true;
+    }
+    if (visitedClasses.contains(modelClass)) {
+      // This is to prevent infinite recursion when the composed schemas have
+      // a circular dependency.
+      return false;
+    }
+    visitedClasses.add(modelClass);
+
+    // Traverse the oneOf/anyOf composed schemas.
+    Map<String, GenericType> descendants = modelDescendants.get(modelClass);
+    if (descendants != null) {
+      for (GenericType childType : descendants.values()) {
+        if (isInstanceOf(childType.getRawType(), inst, visitedClasses)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   * A map of discriminators for all model classes.
+   */
+  private static Map<Class<?>, ClassDiscriminatorMapping> modelDiscriminators = new HashMap<Class<?>, ClassDiscriminatorMapping>();
+
+  /**
+   * A map of oneOf/anyOf descendants for each model class.
+   */
+  private static Map<Class<?>, Map<String, GenericType>> modelDescendants = new HashMap<Class<?>, Map<String, GenericType>>();
+
+  /**
+    * Register a model class discriminator.
+    *
+    * @param modelClass the model class
+    * @param discriminatorPropertyName the name of the discriminator property
+    * @param mappings a map with the discriminator mappings.
+    */
+  public static void registerDiscriminator(Class<?> modelClass, String discriminatorPropertyName, Map<String, Class<?>> mappings) {
+    ClassDiscriminatorMapping m = new ClassDiscriminatorMapping(modelClass, discriminatorPropertyName, mappings);
+    modelDiscriminators.put(modelClass, m);
+  }
+
+  /**
+    * Register the oneOf/anyOf descendants of the modelClass.
+    *
+    * @param modelClass the model class
+    * @param descendants a map of oneOf/anyOf descendants.
+    */
+  public static void registerDescendants(Class<?> modelClass, Map<String, GenericType> descendants) {
+    modelDescendants.put(modelClass, descendants);
+  }
+
+  private static JSON json;
+
+  static
+  {
+    json = new JSON();
+  }
+
+  /**
+    * Get the default JSON instance.
+    *
+    * @return the default JSON instance
+    */
+  public static JSON getDefault() {
+    return json;
+  }
+
+  /**
+    * Set the default JSON instance.
+    *
+    * @param json JSON instance to be used
+    */
+  public static void setDefault(JSON json) {
+    JSON.json = json;
+  }
 }
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/api.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/api.mustache
index e6e83d3550b80ad81b0b325b13f60eb6967e9947..666430c834e15dad1a59aa2bdee8308b283209c7 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/api.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/api.mustache
@@ -1,9 +1,8 @@
-//overloaded template file within library folder to add this comment
-
 package {{package}};
 
 import {{invokerPackage}}.ApiException;
 import {{invokerPackage}}.ApiClient;
+import {{invokerPackage}}.ApiResponse;
 import {{invokerPackage}}.Configuration;
 import {{invokerPackage}}.Pair;
 
@@ -17,8 +16,8 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-{{/fullJavaUtil}}
 
+{{/fullJavaUtil}}
 {{>generatedAnnotation}}
 {{#operations}}
 public class {{classname}} {
@@ -32,15 +31,26 @@ public class {{classname}} {
     this.apiClient = apiClient;
   }
 
+  /**
+   * Get the API cilent
+   *
+   * @return API client
+   */
   public ApiClient getApiClient() {
     return apiClient;
   }
 
+  /**
+   * Set the API cilent
+   *
+   * @param apiClient an instance of API client
+   */
   public void setApiClient(ApiClient apiClient) {
     this.apiClient = apiClient;
   }
 
   {{#operation}}
+  {{^vendorExtensions.x-group-parameters}}
   /**
    * {{summary}}
    * {{notes}}
@@ -51,8 +61,61 @@ public class {{classname}} {
    * @return {{returnType}}
    {{/returnType}}
    * @throws ApiException if fails to make API call
+   {{#responses.0}}
+   * @http.response.details
+     <table summary="Response Details" border="1">
+       <tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
+       {{#responses}}
+       <tr><td> {{code}} </td><td> {{message}} </td><td> {{#headers}} * {{baseName}} - {{description}} <br> {{/headers}}{{^headers.0}} - {{/headers.0}} </td></tr>
+       {{/responses}}
+     </table>
+   {{/responses.0}}
+   {{#isDeprecated}}
+   * @deprecated
+   {{/isDeprecated}}
+   {{#externalDocs}}
+   * {{description}}
+   * @see <a href="{{url}}">{{summary}} Documentation</a>
+   {{/externalDocs}}
    */
+  {{#isDeprecated}}
+  @Deprecated
+  {{/isDeprecated}}
   public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException {
+    {{#returnType}}return {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}){{#returnType}}.getData(){{/returnType}};
+  }
+  {{/vendorExtensions.x-group-parameters}}
+
+  {{^vendorExtensions.x-group-parameters}}
+  /**
+   * {{summary}}
+   * {{notes}}
+   {{#allParams}}
+   * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
+   {{/allParams}}
+   * @return ApiResponse&lt;{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/returnType}}&gt;
+   * @throws ApiException if fails to make API call
+   {{#responses.0}}
+   * @http.response.details
+     <table summary="Response Details" border="1">
+       <tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
+       {{#responses}}
+       <tr><td> {{code}} </td><td> {{message}} </td><td> {{#headers}} * {{baseName}} - {{description}} <br> {{/headers}}{{^headers.0}} - {{/headers.0}} </td></tr>
+       {{/responses}}
+     </table>
+   {{/responses.0}}
+   {{#isDeprecated}}
+   * @deprecated
+   {{/isDeprecated}}
+   {{#externalDocs}}
+   * {{description}}
+   * @see <a href="{{url}}">{{summary}} Documentation</a>
+   {{/externalDocs}}
+   */
+  {{#isDeprecated}}
+  @Deprecated
+  {{/isDeprecated}}
+  public{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}private{{/vendorExtensions.x-group-parameters}} ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException {
     Object localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
     {{#allParams}}{{#required}}
     // verify the required parameter '{{paramName}}' is set
@@ -61,12 +124,13 @@ public class {{classname}} {
     }
     {{/required}}{{/allParams}}
     // create path and map variables
-    String localVarPath = "{{{path}}}".replaceAll("\\{format\\}","json"){{#pathParams}}
+    String localVarPath = "{{{path}}}"{{#pathParams}}
       .replaceAll("\\{" + "{{baseName}}" + "\\}", apiClient.escapeString({{{paramName}}}.toString())){{/pathParams}};
 
     // query params
     {{javaUtilPrefix}}List<Pair> localVarQueryParams = new {{javaUtilPrefix}}ArrayList<Pair>();
     {{javaUtilPrefix}}Map<String, String> localVarHeaderParams = new {{javaUtilPrefix}}HashMap<String, String>();
+    {{javaUtilPrefix}}Map<String, String> localVarCookieParams = new {{javaUtilPrefix}}HashMap<String, String>();
     {{javaUtilPrefix}}Map<String, Object> localVarFormParams = new {{javaUtilPrefix}}HashMap<String, Object>();
 
     {{#queryParams}}
@@ -77,6 +141,10 @@ public class {{classname}} {
       localVarHeaderParams.put("{{baseName}}", apiClient.parameterToString({{paramName}}));
     {{/headerParams}}
 
+    {{#cookieParams}}if ({{paramName}} != null)
+      localVarCookieParams.put("{{baseName}}", apiClient.parameterToString({{paramName}}));
+    {{/cookieParams}}
+
     {{#formParams}}if ({{paramName}} != null)
       localVarFormParams.put("{{baseName}}", {{paramName}});
     {{/formParams}}
@@ -95,11 +163,100 @@ public class {{classname}} {
 
     {{#returnType}}
     GenericType<{{{returnType}}}> localVarReturnType = new GenericType<{{{returnType}}}>() {};
-    return apiClient.invokeAPI(localVarPath, "{{httpMethod}}", localVarQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType);
-    {{/returnType}}{{^returnType}}
-    apiClient.invokeAPI(localVarPath, "{{httpMethod}}", localVarQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAccept, localVarContentType, localVarAuthNames, null);
+
     {{/returnType}}
+    return apiClient.invokeAPI("{{classname}}.{{operationId}}", localVarPath, "{{httpMethod}}", localVarQueryParams, localVarPostBody,
+                               localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAccept, localVarContentType,
+                               localVarAuthNames, {{#returnType}}localVarReturnType{{/returnType}}{{^returnType}}null{{/returnType}}, {{#bodyParam}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/bodyParam}}{{^bodyParam}}false{{/bodyParam}});
+  }
+  {{#vendorExtensions.x-group-parameters}}
+
+  public class API{{operationId}}Request {
+    {{#allParams}}
+    private {{#isRequired}}final {{/isRequired}}{{{dataType}}} {{paramName}};
+    {{/allParams}}
+
+    private API{{operationId}}Request({{#pathParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/pathParams}}) {
+      {{#pathParams}}
+      this.{{paramName}} = {{paramName}};
+      {{/pathParams}}
+    }
+    {{#allParams}}
+    {{^isPathParam}}
+
+    /**
+     * Set {{paramName}}
+     * @param {{paramName}} {{description}} ({{^required}}optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}{{/required}}{{#required}}required{{/required}})
+     * @return API{{operationId}}Request
+     */
+    public API{{operationId}}Request {{paramName}}({{{dataType}}} {{paramName}}) {
+      this.{{paramName}} = {{paramName}};
+      return this;
+    }
+    {{/isPathParam}}
+    {{/allParams}}
+
+    /**
+     * Execute {{operationId}} request
+     {{#returnType}}* @return {{.}}{{/returnType}}
+     * @throws ApiException if fails to make API call
+     {{#responses.0}}
+     * @http.response.details
+       <table summary="Response Details" border="1">
+         <tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
+         {{#responses}}
+         <tr><td> {{code}} </td><td> {{message}} </td><td> {{#headers}} * {{baseName}} - {{description}} <br> {{/headers}}{{^headers.0}} - {{/headers.0}} </td></tr>
+         {{/responses}}
+       </table>
+     {{/responses.0}}
+     {{#isDeprecated}}* @deprecated{{/isDeprecated}}
+     */
+    {{#isDeprecated}}@Deprecated{{/isDeprecated}}
+    public {{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}void{{/returnType}} execute() throws ApiException {
+      {{#returnType}}return {{/returnType}}this.executeWithHttpInfo().getData();
+    }
+
+    /**
+     * Execute {{operationId}} request with HTTP info returned
+     * @return ApiResponse&lt;{{#returnType}}{{.}}{{/returnType}}{{^returnType}}Void{{/returnType}}&gt;
+     * @throws ApiException if fails to make API call
+     {{#responses.0}}
+     * @http.response.details
+       <table summary="Response Details" border="1">
+         <tr><td> Status Code </td><td> Description </td><td> Response Headers </td></tr>
+         {{#responses}}
+         <tr><td> {{code}} </td><td> {{message}} </td><td> {{#headers}} * {{baseName}} - {{description}} <br> {{/headers}}{{^headers.0}} - {{/headers.0}} </td></tr>
+         {{/responses}}
+       </table>
+     {{/responses.0}}
+     {{#isDeprecated}}
+     * @deprecated{{/isDeprecated}}
+     */
+    {{#isDeprecated}}
+    @Deprecated
+    {{/isDeprecated}}
+    public ApiResponse<{{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> executeWithHttpInfo() throws ApiException {
+      return {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
+    }
+  }
+
+  /**
+   * {{summary}}
+   * {{notes}}{{#pathParams}}
+   * @param {{paramName}} {{description}} (required){{/pathParams}}
+   * @return {{operationId}}Request
+   * @throws ApiException if fails to make API call
+   {{#isDeprecated}}* @deprecated{{/isDeprecated}}
+   {{#externalDocs}}* {{description}}
+   * @see <a href="{{url}}">{{summary}} Documentation</a>{{/externalDocs}}
+   */
+  {{#isDeprecated}}
+  @Deprecated
+  {{/isDeprecated}}
+  public API{{operationId}}Request {{operationId}}({{#pathParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/pathParams}}) throws ApiException {
+    return new API{{operationId}}Request({{#pathParams}}{{paramName}}{{^-last}}, {{/-last}}{{/pathParams}});
   }
+  {{/vendorExtensions.x-group-parameters}}
   {{/operation}}
 }
 {{/operations}}
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.gradle.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.gradle.mustache
index c76ec3218088e7badd323d336b4cd1d9b775a05e..378de9fb1e1f44b7394df4e29059405bc2d81a61 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.gradle.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.gradle.mustache
@@ -1,5 +1,3 @@
-//overloaded template file within library folder to add this comment
-
 apply plugin: 'idea'
 apply plugin: 'eclipse'
 
@@ -8,11 +6,12 @@ version = '{{artifactVersion}}'
 
 buildscript {
     repositories {
+        maven { url "https://repo1.maven.org/maven2" }
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.5.+'
-        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
+        classpath 'com.android.tools.build:gradle:2.3.+'
+        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
     }
 }
 
@@ -27,18 +26,13 @@ if(hasProperty('target') && target == 'android') {
     apply plugin: 'com.github.dcendents.android-maven'
 
     android {
-        compileSdkVersion 23
-        buildToolsVersion '23.0.2'
+        compileSdkVersion 25
+        buildToolsVersion '25.0.2'
         defaultConfig {
             minSdkVersion 14
-            targetSdkVersion 23
+            targetSdkVersion 25
         }
         compileOptions {
-            {{#supportJava6}}
-            sourceCompatibility JavaVersion.VERSION_1_6
-            targetCompatibility JavaVersion.VERSION_1_6
-            {{/supportJava6}}
-            {{^supportJava6}}
             {{#java8}}
             sourceCompatibility JavaVersion.VERSION_1_8
             targetCompatibility JavaVersion.VERSION_1_8
@@ -47,7 +41,6 @@ if(hasProperty('target') && target == 'android') {
             sourceCompatibility JavaVersion.VERSION_1_7
             targetCompatibility JavaVersion.VERSION_1_7
             {{/java8}}
-            {{/supportJava6}}
         }
 
         // Rename the aar correctly
@@ -91,11 +84,6 @@ if(hasProperty('target') && target == 'android') {
 
     apply plugin: 'java'
     apply plugin: 'maven'
-    {{#supportJava6}}
-    sourceCompatibility = JavaVersion.VERSION_1_6
-    targetCompatibility = JavaVersion.VERSION_1_6
-    {{/supportJava6}}
-    {{^supportJava6}}
     {{#java8}}
     sourceCompatibility = JavaVersion.VERSION_1_8
     targetCompatibility = JavaVersion.VERSION_1_8
@@ -104,7 +92,6 @@ if(hasProperty('target') && target == 'android') {
     sourceCompatibility = JavaVersion.VERSION_1_7
     targetCompatibility = JavaVersion.VERSION_1_7
     {{/java8}}
-    {{/supportJava6}}
 
     install {
         repositories.mavenInstaller {
@@ -119,38 +106,61 @@ if(hasProperty('target') && target == 'android') {
 }
 
 ext {
-    swagger_annotations_version = "1.5.8"
-    jackson_version = "2.7.5"
-    jersey_version = "2.22.2"
-    {{^java8}}
-    jodatime_version = "2.9.4"
-    {{/java8}}
-    {{#supportJava6}}
-    commons_io_version=2.5
-    commons_lang3_version=3.5
-    {{/supportJava6}}
-    junit_version = "4.13"
+    swagger_annotations_version = "1.5.22"
+    jackson_version = "2.10.5"
+    jackson_databind_version = "2.10.5.1"
+    {{#openApiNullable}}
+    jackson_databind_nullable_version = "0.2.1"
+    {{/openApiNullable}}
+    jersey_version = "2.27"
+    junit_version = "4.13.1"
+    {{#threetenbp}}
+    threetenbp_version = "2.9.10"
+    {{/threetenbp}}
+    {{#hasOAuthMethods}}
+    scribejava_apis_version = "6.9.0"
+    {{/hasOAuthMethods}}
+    {{#hasHttpSignatureMethods}}
+    tomitribe_http_signatures_version = "1.5"
+    {{/hasHttpSignatureMethods}}
 }
 
 dependencies {
     implementation "io.swagger:swagger-annotations:$swagger_annotations_version"
+    implementation "com.google.code.findbugs:jsr305:3.0.2"
     implementation "org.glassfish.jersey.core:jersey-client:$jersey_version"
+    implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version"
     implementation "org.glassfish.jersey.media:jersey-media-multipart:$jersey_version"
     implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jersey_version"
+    implementation "org.glassfish.jersey.connectors:jersey-apache-connector:$jersey_version"
     implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version"
     implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version"
-    implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
+    implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_databind_version"
+    {{#openApiNullable}}
+    implementation "org.openapitools:jackson-databind-nullable:$jackson_databind_nullable_version"
+    {{/openApiNullable}}
+    {{#joda}}
+    implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version"
+    {{/joda}}
     {{#java8}}
     implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version"
     {{/java8}}
+    {{#hasOAuthMethods}}
+    implementation "com.github.scribejava:scribejava-apis:$scribejava_apis_version"
+    {{/hasOAuthMethods}}
+    {{#hasHttpSignatureMethods}}
+    implementation "org.tomitribe:tomitribe-http-signatures:$tomitribe_http_signatures_version"
+    {{/hasHttpSignatureMethods}}
+    {{#threetenbp}}
+    implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$threetenbp_version"
+    {{/threetenbp}}
     {{^java8}}
-    implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version"
-    implementation "joda-time:joda-time:$jodatime_version"
     implementation "com.brsanthu:migbase64:2.2"
     {{/java8}}
-    {{#supportJava6}}
-    implementation "commons-io:commons-io:$commons_io_version"
-    implementation "org.apache.commons:commons-lang3:$commons_lang3_version"
-    {{/supportJava6}}
+    implementation 'javax.annotation:javax.annotation-api:1.3.2'
     testImplementation "junit:junit:$junit_version"
 }
+
+javadoc {
+    options.tags = [ "http.response.details:a:Http Response Details" ]
+}
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.sbt.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.sbt.mustache
index 1049751cf3a4797d099423b9b80ee35a7e878ede..9823c3c657e9ae4fac3c6b181758ab21d57fe791 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.sbt.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/build.sbt.mustache
@@ -1,5 +1,3 @@
-//overloaded template file within library folder to add this comment
-
 lazy val root = (project in file(".")).
   settings(
     organization := "{{groupId}}",
@@ -11,26 +9,35 @@ lazy val root = (project in file(".")).
     publishArtifact in (Compile, packageDoc) := false,
     resolvers += Resolver.mavenLocal,
     libraryDependencies ++= Seq(
-      "io.swagger" % "swagger-annotations" % "1.5.8",
-      "org.glassfish.jersey.core" % "jersey-client" % "2.22.2",
-      "org.glassfish.jersey.media" % "jersey-media-multipart" % "2.22.2",
-      "org.glassfish.jersey.media" % "jersey-media-json-jackson" % "2.22.2",
-      "com.fasterxml.jackson.core" % "jackson-core" % "2.7.5",
-      "com.fasterxml.jackson.core" % "jackson-annotations" % "2.7.5",
-      "com.fasterxml.jackson.core" % "jackson-databind" % "2.7.5",
+      "io.swagger" % "swagger-annotations" % "1.5.22",
+      "org.glassfish.jersey.core" % "jersey-client" % "2.27",
+      "org.glassfish.jersey.inject" % "jersey-hk2" % "2.27",
+      "org.glassfish.jersey.media" % "jersey-media-multipart" % "2.27",
+      "org.glassfish.jersey.media" % "jersey-media-json-jackson" % "2.27",
+      "org.glassfish.jersey.connectors" % "jersey-apache-connector" % "2.27",
+      "com.fasterxml.jackson.core" % "jackson-core" % "2.10.5" % "compile",
+      "com.fasterxml.jackson.core" % "jackson-annotations" % "2.10.5.1" % "compile",
+      "com.fasterxml.jackson.core" % "jackson-databind" % "2.10.5.1" % "compile",
+      {{#joda}}
+      "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.9.10" % "compile",
+      {{/joda}}
       {{#java8}}
-	  "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.7.5",
-	  {{/java8}}
-	  {{^java8}}
-      "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.7.5",
-      "joda-time" % "joda-time" % "2.9.4",
+      "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.9.10" % "compile",
+      {{/java8}}
+      {{#threetenbp}}
+      "com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile",
+      {{/threetenbp}}
+      {{#hasOAuthMethods}}
+      "com.github.scribejava" % "scribejava-apis" % "6.9.0" % "compile",
+      {{/hasOAuthMethods}}
+      {{#hasHttpSignatureMethods}}
+      "org.tomitribe" % "tomitribe-http-signatures" % "1.5" % "compile",
+      {{/hasHttpSignatureMethods}}
+      {{^java8}}
       "com.brsanthu" % "migbase64" % "2.2",
       {{/java8}}
-      {{#supportJava6}}
-      "org.apache.commons" % "commons-lang3" % "3.5",
-      "commons-io" % "commons-io" % "2.5",
-      {{/supportJava6}}
-      "junit" % "junit" % "4.13" % "test",
+      "javax.annotation" % "javax.annotation-api" % "1.3.2" % "compile",
+      "junit" % "junit" % "4.13.1" % "test",
       "com.novocode" % "junit-interface" % "0.10" % "test"
     )
   )
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/pom.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/pom.mustache
index 3e1a02651469c9a9a3ecd10f716f278bc5e7177d..f36f0cd8817881dffd6b2923cc0e22c7e376ceba 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/pom.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/libraries/jersey2/pom.mustache
@@ -1,5 +1,3 @@
-//overloaded template file within library folder to add this comment
-
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
@@ -15,6 +13,13 @@
         <developerConnection>{{scmDeveloperConnection}}</developerConnection>
         <url>{{scmUrl}}</url>
     </scm>
+{{#parentOverridden}}
+    <parent>
+        <groupId>{{{parentGroupId}}}</groupId>
+        <artifactId>{{{parentArtifactId}}}</artifactId>
+        <version>{{{parentVersion}}}</version>
+    </parent>
+{{/parentOverridden}}
 
     <licenses>
         <license>
@@ -58,7 +63,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.12</version>
+                <version>3.0.0-M4</version>
                 <configuration>
                     <systemProperties>
                         <property>
@@ -68,7 +73,8 @@
                     </systemProperties>
                     <argLine>-Xms512m -Xmx1500m</argLine>
                     <parallel>methods</parallel>
-                    <forkMode>pertest</forkMode>
+                    <threadCount>10</threadCount>
+                    <trimStackTrace>false</trimStackTrace>
                 </configuration>
             </plugin>
             <plugin>
@@ -106,6 +112,7 @@
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.10</version>
                 <executions>
                     <execution>
                         <id>add_sources</id>
@@ -115,8 +122,7 @@
                         </goals>
                         <configuration>
                             <sources>
-                                <source>
-                                src/main/java</source>
+                                <source>src/main/java</source>
                             </sources>
                         </configuration>
                     </execution>
@@ -128,8 +134,7 @@
                         </goals>
                         <configuration>
                             <sources>
-                                <source>
-                                src/test/java</source>
+                                <source>src/test/java</source>
                             </sources>
                         </configuration>
                     </execution>
@@ -138,7 +143,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>2.5.1</version>
+                <version>3.8.1</version>
                 <configuration>
                     {{#java8}}
                         <source>1.8</source>
@@ -148,15 +153,19 @@
                         <source>1.7</source>
                         <target>1.7</target>
                     {{/java8}}
+                    <fork>true</fork>
+                    <meminitial>128m</meminitial>
+                    <maxmem>512m</maxmem>
+                    <compilerArgs>
+                        <arg>-Xlint:all</arg>
+                        <arg>-J-Xss4m</arg><!-- Compiling the generated JSON.java file may require larger stack size. -->
+                    </compilerArgs>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-javadoc-plugin</artifactId>
                 <version>3.1.1</version>
-                <configuration>
-                    <doclint>none</doclint>
-                </configuration>
                 <executions>
                     <execution>
                         <id>attach-javadocs</id>
@@ -165,6 +174,22 @@
                         </goals>
                     </execution>
                 </executions>
+                <configuration>
+                    <doclint>none</doclint>
+                    {{#java8}}
+                        <source>1.8</source>
+                    {{/java8}}
+                    {{^java8}}
+                        <source>1.7</source>
+                    {{/java8}}
+                    <tags>
+                        <tag>
+                            <name>http.response.details</name>
+                            <placement>a</placement>
+                            <head>Http Response Details:</head>
+                        </tag>
+                    </tags>
+                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
@@ -210,7 +235,14 @@
         <dependency>
             <groupId>io.swagger</groupId>
             <artifactId>swagger-annotations</artifactId>
-            <version>${swagger-core-version}</version>
+            <version>${swagger-annotations-version}</version>
+        </dependency>
+
+        <!-- @Nullable annotation -->
+        <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+            <version>3.0.2</version>
         </dependency>
 
         <!-- HTTP client: jersey-client -->
@@ -219,6 +251,11 @@
             <artifactId>jersey-client</artifactId>
             <version>${jersey-version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.inject</groupId>
+            <artifactId>jersey-hk2</artifactId>
+            <version>${jersey-version}</version>
+        </dependency>
         <dependency>
             <groupId>org.glassfish.jersey.media</groupId>
             <artifactId>jersey-media-multipart</artifactId>
@@ -244,49 +281,86 @@
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
+            <version>${jackson-databind-version}</version>
+        </dependency>
+        {{#openApiNullable}}
+        <dependency>
+            <groupId>org.openapitools</groupId>
+            <artifactId>jackson-databind-nullable</artifactId>
+            <version>${jackson-databind-nullable-version}</version>
+        </dependency>
+        {{/openApiNullable}}
+        {{#withXml}}
+        <!-- XML processing: JAXB -->
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-jaxb</artifactId>
+            <version>${jersey-version}</version>
+        </dependency>
+        {{/withXml}}
+        {{#joda}}
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-joda</artifactId>
             <version>${jackson-version}</version>
         </dependency>
+        {{/joda}}
         {{#java8}}
-            <dependency>
-                <groupId>com.fasterxml.jackson.datatype</groupId>
-                <artifactId>jackson-datatype-jsr310</artifactId>
-                <version>${jackson-version}</version>
-            </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>${jackson-version}</version>
+        </dependency>
         {{/java8}}
+        {{#threetenbp}}
+        <dependency>
+            <groupId>com.github.joschi.jackson</groupId>
+            <artifactId>jackson-datatype-threetenbp</artifactId>
+            <version>${threetenbp-version}</version>
+        </dependency>
+        {{/threetenbp}}
         {{^java8}}
-            <dependency>
-                <groupId>com.fasterxml.jackson.datatype</groupId>
-                <artifactId>jackson-datatype-joda</artifactId>
-                <version>${jackson-version}</version>
-            </dependency>
-            <dependency>
-                <groupId>joda-time</groupId>
-                <artifactId>joda-time</artifactId>
-                <version>${jodatime-version}</version>
-            </dependency>
-
-            <!-- Base64 encoding that works in both JVM and Android -->
-            <dependency>
-                <groupId>com.brsanthu</groupId>
-                <artifactId>migbase64</artifactId>
-                <version>2.2</version>
-            </dependency>
+        <!-- Base64 encoding that works in both JVM and Android -->
+        <dependency>
+            <groupId>com.brsanthu</groupId>
+            <artifactId>migbase64</artifactId>
+            <version>2.2</version>
+        </dependency>
         {{/java8}}
-
-        {{#supportJava6}}
-            <dependency>
-                <groupId>org.apache.commons</groupId>
-                <artifactId>commons-lang3</artifactId>
-                <version>${commons_lang3_version}</version>
-            </dependency>
-
-            <dependency>
-                <groupId>commons-io</groupId>
-                <artifactId>commons-io</artifactId>
-                <version>${commons_io_version}</version>
-            </dependency>
-        {{/supportJava6}}
-
+        {{#hasHttpSignatureMethods}}
+        <dependency>
+            <groupId>org.tomitribe</groupId>
+            <artifactId>tomitribe-http-signatures</artifactId>
+            <version>${http-signature-version}</version>
+        </dependency>
+        {{/hasHttpSignatureMethods}}
+        {{#hasOAuthMethods}}
+        <dependency>
+            <groupId>com.github.scribejava</groupId>
+            <artifactId>scribejava-apis</artifactId>
+            <version>${scribejava-apis-version}</version>
+        </dependency>
+        {{/hasOAuthMethods}}
+        {{#useBeanValidation}}
+        <!-- Bean Validation API support -->
+        <dependency>
+            <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+            <version>1.1.0.Final</version>
+            <scope>provided</scope>
+        </dependency>
+        {{/useBeanValidation}}
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <version>${javax-annotation-version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-apache-connector</artifactId>
+            <version>${jersey-version}</version>
+        </dependency>
         <!-- test dependencies -->
         <dependency>
             <groupId>junit</groupId>
@@ -297,17 +371,21 @@
     </dependencies>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <swagger-core-version>1.5.18</swagger-core-version>
-        <jersey-version>2.22.2</jersey-version>
-        <jackson-version>2.8.9</jackson-version>
-        {{^java8}}
-            <jodatime-version>2.9.4</jodatime-version>
-        {{/java8}}
-        {{#supportJava6}}
-            <commons_io_version>2.5</commons_io_version>
-            <commons_lang3_version>3.5</commons_lang3_version>
-        {{/supportJava6}}
-        <maven-plugin-version>1.0.0</maven-plugin-version>
-        <junit-version>4.13</junit-version>
+        <swagger-annotations-version>1.6.1</swagger-annotations-version>
+        <jersey-version>2.30.1</jersey-version>
+        <jackson-version>2.10.5</jackson-version>
+        <jackson-databind-version>2.10.5.1</jackson-databind-version>
+        <jackson-databind-nullable-version>0.2.1</jackson-databind-nullable-version>
+        {{#threetenbp}}
+        <threetenbp-version>2.9.10</threetenbp-version>
+        {{/threetenbp}}
+        <javax-annotation-version>1.3.2</javax-annotation-version>
+        <junit-version>4.13.1</junit-version>
+        {{#hasHttpSignatureMethods}}
+        <http-signature-version>1.5</http-signature-version>
+        {{/hasHttpSignatureMethods}}
+        {{#hasOAuthMethods}}
+        <scribejava-apis-version>6.9.0</scribejava-apis-version>
+        {{/hasOAuthMethods}}
     </properties>
 </project>
diff --git a/modules/openapi-generator/src/test/resources/2_0/templates/Java/model.mustache b/modules/openapi-generator/src/test/resources/2_0/templates/Java/model.mustache
index 07adf19139f65e69f50f056efbb87bf31e3a6011..8fd078eb3d62abc4a22028404567195b56a75bfe 100644
--- a/modules/openapi-generator/src/test/resources/2_0/templates/Java/model.mustache
+++ b/modules/openapi-generator/src/test/resources/2_0/templates/Java/model.mustache
@@ -1,31 +1,54 @@
-//overloaded main template file to add this comment
-
 {{>licenseInfo}}
 
 package {{package}};
 
-{{^supportJava6}}
+{{#useReflectionEqualsHashCode}}
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+{{/useReflectionEqualsHashCode}}
 import java.util.Objects;
-{{/supportJava6}}
-{{#supportJava6}}
-import org.apache.commons.lang3.ObjectUtils;
-{{/supportJava6}}
+import java.util.Arrays;
 {{#imports}}
 import {{import}};
 {{/imports}}
 {{#serializableModel}}
 import java.io.Serializable;
 {{/serializableModel}}
+{{#jackson}}
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+{{#withXml}}
+import com.fasterxml.jackson.dataformat.xml.annotation.*;
+{{/withXml}}
+{{/jackson}}
+{{#withXml}}
+import javax.xml.bind.annotation.*;
+{{/withXml}}
+{{#jsonb}}
+import java.lang.reflect.Type;
+import javax.json.bind.annotation.JsonbTypeDeserializer;
+import javax.json.bind.annotation.JsonbTypeSerializer;
+import javax.json.bind.serializer.DeserializationContext;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
+import javax.json.bind.serializer.SerializationContext;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonParser;
+import javax.json.bind.annotation.JsonbProperty;
+{{/jsonb}}
 {{#parcelableModel}}
 import android.os.Parcelable;
 import android.os.Parcel;
 {{/parcelableModel}}
 {{#useBeanValidation}}
 import javax.validation.constraints.*;
+import javax.validation.Valid;
 {{/useBeanValidation}}
+{{#performBeanValidation}}
+import org.hibernate.validator.constraints.*;
+{{/performBeanValidation}}
 
 {{#models}}
 {{#model}}
-{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{>pojo}}{{/isEnum}}
+{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}}{{/isEnum}}
 {{/model}}
 {{/models}}
diff --git a/samples/server/petstore/scala-akka-http-server/.openapi-generator/FILES b/samples/server/petstore/scala-akka-http-server/.openapi-generator/FILES
new file mode 100644
index 0000000000000000000000000000000000000000..cfcbab175e5d96f627a5f846f9bcab417bc1281f
--- /dev/null
+++ b/samples/server/petstore/scala-akka-http-server/.openapi-generator/FILES
@@ -0,0 +1,15 @@
+README.md
+build.sbt
+src/main/scala/org/openapitools/server/AkkaHttpHelper.scala
+src/main/scala/org/openapitools/server/Controller.scala
+src/main/scala/org/openapitools/server/MultipartDirectives.scala
+src/main/scala/org/openapitools/server/StringDirectives.scala
+src/main/scala/org/openapitools/server/api/PetApi.scala
+src/main/scala/org/openapitools/server/api/StoreApi.scala
+src/main/scala/org/openapitools/server/api/UserApi.scala
+src/main/scala/org/openapitools/server/model/ApiResponse.scala
+src/main/scala/org/openapitools/server/model/Category.scala
+src/main/scala/org/openapitools/server/model/Order.scala
+src/main/scala/org/openapitools/server/model/Pet.scala
+src/main/scala/org/openapitools/server/model/Tag.scala
+src/main/scala/org/openapitools/server/model/User.scala
diff --git a/samples/server/petstore/scala-akka-http-server/.openapi-generator/VERSION b/samples/server/petstore/scala-akka-http-server/.openapi-generator/VERSION
index d99e7162d01f35766e7a53f78b6acb6f7d84f1c3..d509cc92aa80dae7c43ef460023b9f552042c418 100644
--- a/samples/server/petstore/scala-akka-http-server/.openapi-generator/VERSION
+++ b/samples/server/petstore/scala-akka-http-server/.openapi-generator/VERSION
@@ -1 +1 @@
-5.0.0-SNAPSHOT
\ No newline at end of file
+5.1.1-SNAPSHOT
\ No newline at end of file
diff --git a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/MultipartDirectives.scala b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/MultipartDirectives.scala
index 79891d7095a80aff7b22549c76c5cce1d0dc61a0..2ebbd943db2f55dba0e12bccb7ab6756eb2e4a7e 100644
--- a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/MultipartDirectives.scala
+++ b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/MultipartDirectives.scala
@@ -1,6 +1,7 @@
 package org.openapitools.server
 
 import java.io.File
+import java.nio.file.Files
 
 import akka.annotation.ApiMayChange
 import akka.http.scaladsl.model.Multipart.FormData
@@ -69,7 +70,7 @@ trait MultipartDirectives {
 
 object MultipartDirectives extends MultipartDirectives with FileUploadDirectives {
   val tempFileFromFileInfo: FileInfo => File = {
-    file: FileInfo => File.createTempFile(file.fileName, ".tmp")
+    file: FileInfo => Files.createTempFile(file.fileName, ".tmp").toFile()
   }
 }