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<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/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{{/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<{{#returnType}}{{.}}{{/returnType}}{{^returnType}}Void{{/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 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() } }