[Java-VertX] Java Vertx client (#6204)

* #6165 - Java Vertx client

* #6165 - Java Vertx client (samples)

* #6165 - Java Vertx client (tests generation)

* #6165 - Java Vertx client (fixed test samples)
This commit is contained in:
lopesmcc
2017-07-31 13:04:11 +01:00
committed by wing328
parent be9a9a3837
commit 66d48a0c71
133 changed files with 13164 additions and 3 deletions
@@ -0,0 +1,599 @@
package {{invokerPackage}};
import {{invokerPackage}}.auth.Authentication;
import {{invokerPackage}}.auth.HttpBasicAuth;
import {{invokerPackage}}.auth.ApiKeyAuth;
import {{invokerPackage}}.auth.OAuth;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.vertx.core.*;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.file.AsyncFile;
import io.vertx.core.file.FileSystem;
import io.vertx.core.file.OpenOptions;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import java.text.DateFormat;
import java.util.*;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.stream.Collectors.toMap;
{{>generatedAnnotation}}
public class ApiClient {
private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?");
private static final OpenOptions FILE_DOWNLOAD_OPTIONS = new OpenOptions().setCreate(true).setTruncateExisting(true);
private final Vertx vertx;
private MultiMap defaultHeaders = MultiMap.caseInsensitiveMultiMap();
private Map<String, Authentication> authentications;
private WebClient webClient;
private String basePath = "{{{basePath}}}";
private DateFormat dateFormat;
private ObjectMapper objectMapper;
private String downloadsDir = "";
public ApiClient(Vertx vertx, JsonObject config) {
Objects.requireNonNull(vertx, "Vertx must not be null");
Objects.requireNonNull(config, "Config must not be null");
this.vertx = vertx;
// Use RFC3339 format for date and datetime.
// See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14
this.dateFormat = new RFC3339DateFormat();
// Use UTC as the default time zone.
this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
// Build object mapper
this.objectMapper = new ObjectMapper();
this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
this.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
this.objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
this.objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
this.objectMapper.registerModule(new JavaTimeModule());
this.objectMapper.setDateFormat(dateFormat);
// Setup authentications (key: authentication name, value: authentication).
this.authentications = new HashMap<>();{{#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}}
// Prevent the authentications from being modified.
this.authentications = Collections.unmodifiableMap(authentications);
// Configurations
this.basePath = config.getString("basePath", this.basePath);
this.downloadsDir = config.getString("downloadsDir", this.downloadsDir);
// Build WebClient
this.webClient = buildWebClient(vertx, config);
}
public Vertx getVertx() {
return vertx;
}
public ObjectMapper getObjectMapper() {
return objectMapper;
}
public ApiClient setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
return this;
}
public WebClient getWebClient() {
return webClient;
}
public ApiClient setWebClient(WebClient webClient) {
this.webClient = webClient;
return this;
}
public String getBasePath() {
return basePath;
}
public ApiClient setBasePath(String basePath) {
this.basePath = basePath;
return this;
}
public String getDownloadsDir() {
return downloadsDir;
}
public ApiClient setDownloadsDir(String downloadsDir) {
this.downloadsDir = downloadsDir;
return this;
}
public MultiMap getDefaultHeaders() {
return defaultHeaders;
}
public ApiClient addDefaultHeader(String key, String value) {
defaultHeaders.add(key, value);
return this;
}
/**
* Get authentications (key: authentication name, value: authentication).
*
* @return Map of authentication object
*/
public Map<String, Authentication> getAuthentications() {
return authentications;
}
/**
* Get authentication for the given name.
*
* @param authName The authentication name
* @return The authentication, null if not found
*/
public Authentication getAuthentication(String authName) {
return authentications.get(authName);
}
/**
* Helper method to set username for the first HTTP basic authentication.
*
* @param username Username
*/
public ApiClient setUsername(String username) {
for (Authentication auth : authentications.values()) {
if (auth instanceof HttpBasicAuth) {
((HttpBasicAuth) auth).setUsername(username);
return this;
}
}
throw new RuntimeException("No HTTP basic authentication configured!");
}
/**
* Helper method to set password for the first HTTP basic authentication.
*
* @param password Password
*/
public ApiClient setPassword(String password) {
for (Authentication auth : authentications.values()) {
if (auth instanceof HttpBasicAuth) {
((HttpBasicAuth) auth).setPassword(password);
return this;
}
}
throw new RuntimeException("No HTTP basic authentication configured!");
}
/**
* Helper method to set API key value for the first API key authentication.
*
* @param apiKey API key
*/
public ApiClient setApiKey(String apiKey) {
for (Authentication auth : authentications.values()) {
if (auth instanceof ApiKeyAuth) {
((ApiKeyAuth) auth).setApiKey(apiKey);
return this;
}
}
throw new RuntimeException("No API key authentication configured!");
}
/**
* Helper method to set API key prefix for the first API key authentication.
*
* @param apiKeyPrefix API key prefix
*/
public ApiClient setApiKeyPrefix(String apiKeyPrefix) {
for (Authentication auth : authentications.values()) {
if (auth instanceof ApiKeyAuth) {
((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix);
return this;
}
}
throw new RuntimeException("No API key authentication configured!");
}
/**
* Helper method to set access token for the first OAuth2 authentication.
*
* @param accessToken Access token
*/
public ApiClient setAccessToken(String accessToken) {
for (Authentication auth : authentications.values()) {
if (auth instanceof OAuth) {
((OAuth) auth).setAccessToken(accessToken);
return this;
}
}
throw new RuntimeException("No OAuth2 authentication configured!");
}
/**
* Format the given Date object into string.
*
* @param date Date
* @return Date in string format
*/
public String formatDate(Date date) {
return dateFormat.format(date);
}
/**
* Format the given parameter object into string.
*
* @param param Object
* @return Object in string format
*/
public String parameterToString(Object param) {
if (param == null) {
return "";
} else if (param instanceof Date) {
return formatDate((Date) param);
} else if (param instanceof Collection) {
StringBuilder b = new StringBuilder();
for (Object o : (Collection) param) {
if (b.length() > 0) {
b.append(',');
}
b.append(String.valueOf(o));
}
return b.toString();
} else {
return String.valueOf(param);
}
}
/*
* Format to {@code Pair} objects.
* @param collectionFormat Collection format
* @param name Name
* @param value Value
* @return List of pairs
*/
public List<Pair> parameterToPairs(String collectionFormat, String name, Object value) {
List<Pair> params = new ArrayList<Pair>();
// preconditions
if (name == null || name.isEmpty() || value == null) return params;
Collection valueCollection;
if (value instanceof Collection) {
valueCollection = (Collection) value;
} else {
params.add(new Pair(name, parameterToString(value)));
return params;
}
if (valueCollection.isEmpty()) {
return params;
}
// get the collection format (default: csv)
String format = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat);
// create the params based on the collection format
if ("multi".equals(format)) {
for (Object item : valueCollection) {
params.add(new Pair(name, parameterToString(item)));
}
return params;
}
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 = "|";
}
StringBuilder sb = new StringBuilder();
for (Object item : valueCollection) {
sb.append(delimiter);
sb.append(parameterToString(item));
}
params.add(new Pair(name, sb.substring(1)));
return params;
}
/**
* Check if the given MIME is a JSON MIME.
* JSON MIME examples:
* application/json
* application/json; charset=UTF8
* APPLICATION/JSON
* application/vnd.company+json
*
* @param mime MIME
* @return True if the MIME type is JSON
*/
private boolean isJsonMime(String mime) {
String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$";
return mime != null && (mime.matches(jsonMime) || mime.equalsIgnoreCase("application/json-patch+json"));
}
/**
* Select the Accept header's value from the given accepts array:
* if JSON exists in the given array, use it;
* otherwise use all of them (joining into a string)
*
* @param accepts The accepts array to select from
* @return The Accept header to use. If the given array is empty,
* null will be returned (not to set the Accept header explicitly).
*/
protected String selectHeaderAccept(String[] accepts) {
if (accepts.length == 0) {
return null;
}
for (String accept : accepts) {
if (isJsonMime(accept)) {
return accept;
}
}
return StringUtil.join(accepts, ",");
}
/**
* Select the Content-Type header's value from the given array:
* if JSON exists in the given array, use it;
* otherwise use the first one of the array.
*
* @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.
*/
protected String selectHeaderContentType(String[] contentTypes) {
if (contentTypes.length == 0) {
return "application/json";
}
for (String contentType : contentTypes) {
if (isJsonMime(contentType)) {
return contentType;
}
}
return contentTypes[0];
}
public void sendBody(HttpRequest<Buffer> request,
Handler<AsyncResult<HttpResponse<Buffer>>> responseHandler,
Object body) {
if (body instanceof byte[]) {
Buffer buffer = Buffer.buffer((byte[]) body);
request.sendBuffer(buffer, responseHandler);
} else if (body instanceof AsyncFile) {
AsyncFile file = (AsyncFile) body;
request.sendStream(file, responseHandler);
} else {
request.sendJson(body, responseHandler);
}
}
/**
* Invoke API by sending HTTP request with the given options.
*
* @param <T> Type
* @param path The sub-path of the HTTP URL
* @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 formParams The form parameters
* @param accepts The request's Accept headers
* @param contentTypes The request's Content-Type headers
* @param authNames The authentications to apply
* @param returnType The return type into which to deserialize the response
* @param resultHandler The asynchronous response handler
*/
public <T> void invokeAPI(String path, String method, List<Pair> queryParams, Object body, MultiMap headerParams,
Map<String, Object> formParams, String[] accepts, String[] contentTypes, String[] authNames,
TypeReference<T> returnType, Handler<AsyncResult<T>> resultHandler) {
updateParamsForAuth(authNames, queryParams, headerParams);
if (accepts != null) {
headerParams.add(HttpHeaders.ACCEPT, selectHeaderAccept(accepts));
}
if (contentTypes != null) {
headerParams.add(HttpHeaders.CONTENT_TYPE, selectHeaderContentType(contentTypes));
}
HttpMethod httpMethod = HttpMethod.valueOf(method);
HttpRequest<Buffer> request = webClient.requestAbs(httpMethod, basePath + path);
if (httpMethod == HttpMethod.PATCH) {
request.putHeader("X-HTTP-Method-Override", "PATCH");
}
queryParams.forEach(entry -> {
if (entry.getValue() != null) {
request.addQueryParam(entry.getName(), entry.getValue());
}
});
headerParams.forEach(entry -> {
if (entry.getValue() != null) {
request.putHeader(entry.getKey(), entry.getValue());
}
});
defaultHeaders.forEach(entry -> {
if (entry.getValue() != null) {
request.putHeader(entry.getKey(), entry.getValue());
}
});
Handler<AsyncResult<HttpResponse<Buffer>>> responseHandler = buildResponseHandler(returnType, resultHandler);
if (body != null) {
sendBody(request, responseHandler, body);
} else if (formParams != null && !formParams.isEmpty()) {
Map<String, String> formMap = formParams.entrySet().stream().collect(toMap(Map.Entry::getKey, entry -> parameterToString(entry.getValue())));
MultiMap form = MultiMap.caseInsensitiveMultiMap().addAll(formMap);
request.sendForm(form, responseHandler);
} else {
request.send(responseHandler);
}
}
/**
* Sanitize filename by removing path.
* e.g. ../../sun.gif becomes sun.gif
*
* @param filename The filename to be sanitized
* @return The sanitized filename
*/
protected String sanitizeFilename(String filename) {
return filename.replaceAll(".*[/\\\\]", "");
}
/**
* Create a filename from the given headers.
* When the headers have no "Content-Disposition" information, a random UUID name is generated.
*
* @param headers The HTTP response headers
* @return The filename
*/
protected String generateFilename(MultiMap headers) {
String filename = UUID.randomUUID().toString();
String contentDisposition = headers.get("Content-Disposition");
if (contentDisposition != null && !contentDisposition.isEmpty()) {
Matcher matcher = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
if (matcher.find()) {
filename = sanitizeFilename(matcher.group(1));
}
}
return filename;
}
/**
* File Download handling.
*
* @param response The HTTP response
* @param handler The response handler
*/
protected <T> void handleFileDownload(HttpResponse<Buffer> response, Handler<AsyncResult<T>> handler) {
FileSystem fs = getVertx().fileSystem();
String filename = generateFilename(response.headers());
Consumer<String> fileHandler = directory -> {
fs.open(directory + filename, FILE_DOWNLOAD_OPTIONS, asyncFileResult -> {
if (asyncFileResult.succeeded()) {
AsyncFile asyncFile = asyncFileResult.result();
asyncFile.write(response.bodyAsBuffer());
//noinspection unchecked
handler.handle(Future.succeededFuture((T) asyncFile));
} else {
handler.handle(ApiException.fail(asyncFileResult.cause()));
}
});
};
String dir = getDownloadsDir();
if (dir != null && !dir.isEmpty()) {
fs.mkdirs(dir, mkdirResult -> {
String sanitizedFolder = dir.endsWith("/") ? dir : dir + "/";
fileHandler.accept(sanitizedFolder);
});
} else {
fileHandler.accept("");
}
}
/**
* Build a response handler for the HttpResponse.
*
* @param returnType The return type
* @param handler The response handler
* @return The HTTP response handler
*/
protected <T> Handler<AsyncResult<HttpResponse<Buffer>>> buildResponseHandler(TypeReference<T> returnType,
Handler<AsyncResult<T>> handler) {
return response -> {
AsyncResult<T> result;
if (response.succeeded()) {
HttpResponse<Buffer> httpResponse = response.result();
if (httpResponse.statusCode() / 100 == 2) {
if (httpResponse.statusCode() == 204 || returnType == null) {
result = Future.succeededFuture(null);
} else {
T resultContent;
if ("byte[]".equals(returnType.getType().toString())) {
resultContent = (T) httpResponse.body().getBytes();
} else if (AsyncFile.class.equals(returnType.getType())) {
handleFileDownload(httpResponse, handler);
return;
} else {
resultContent = Json.decodeValue(httpResponse.body(), returnType);
}
result = Future.succeededFuture(resultContent);
}
} else {
result = ApiException.fail(httpResponse.statusMessage(), httpResponse.statusCode(), httpResponse.headers(), httpResponse.bodyAsString());
}
} else if (response.cause() instanceof ApiException) {
result = Future.failedFuture(response.cause());
} else {
result = ApiException.fail(500, response.cause() != null ? response.cause().getMessage() : null);
}
handler.handle(result);
};
}
/**
* Build the WebClient used to make HTTP requests.
*
* @param vertx Vertx
* @return WebClient
*/
protected WebClient buildWebClient(Vertx vertx, JsonObject config) {
if (!config.containsKey("userAgent")) {
config.put("userAgent", "{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{artifactVersion}}}/java{{/httpUserAgent}}");
}
return WebClient.create(vertx, new WebClientOptions(config));
}
/**
* Update query and header parameters based on authentication settings.
*
* @param authNames The authentications to apply
*/
protected void updateParamsForAuth(String[] authNames, List<Pair> queryParams, MultiMap headerParams) {
for (String authName : authNames) {
Authentication auth = authentications.get(authName);
if (auth == null) throw new RuntimeException("Authentication undefined: " + authName);
auth.applyToParams(queryParams, headerParams);
}
}
}
@@ -0,0 +1,42 @@
package {{invokerPackage}};
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import java.util.Objects;
public class Configuration {
private static ApiClient defaultApiClient = null;
/**
* Setup the default API client.
* Will be used by API instances when a client is not provided.
*
* @return Default API client
*/
public synchronized static ApiClient setupDefaultApiClient(Vertx vertx, JsonObject config) {
defaultApiClient = new ApiClient(vertx, config);
return defaultApiClient;
}
/**
* Get the default API client, which would be used when creating API
* instances without providing an API client.
*
* @return Default API client
*/
public synchronized static ApiClient getDefaultApiClient() {
return defaultApiClient;
}
/**
* Set the default API client, which would be used when creating API
* instances without providing an API client.
*
* @param apiClient API client
*/
public synchronized static void setDefaultApiClient(ApiClient apiClient) {
defaultApiClient = apiClient;
}
}
@@ -0,0 +1,19 @@
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import java.util.*;
public interface {{classname}} {
{{#operations}}
{{#operation}}
void {{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}Handler<AsyncResult<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>> handler);
{{/operation}}
{{/operations}}
}
@@ -0,0 +1,110 @@
{{>licenseInfo}}
package {{invokerPackage}};
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
{{>generatedAnnotation}}
public class ApiException extends{{#useRuntimeException}} RuntimeException {{/useRuntimeException}}{{^useRuntimeException}} Exception {{/useRuntimeException}}{
private int code = 0;
private MultiMap responseHeaders = null;
private String responseBody = null;
public static <T> AsyncResult<T> fail(int failureCode, String message) {
return Future.failedFuture(new ApiException(failureCode, message));
}
public static <T> AsyncResult<T> fail(Throwable throwable) {
return Future.failedFuture(new ApiException(throwable));
}
public static <T> AsyncResult<T> fail(String message) {
return Future.failedFuture(new ApiException(message));
}
public static <T> AsyncResult<T> fail(String message, Throwable throwable, int code, MultiMap responseHeaders) {
return Future.failedFuture(new ApiException(message, throwable, code, responseHeaders, null));
}
public static <T> AsyncResult<T> fail(String message, Throwable throwable, int code, MultiMap responseHeaders, String responseBody) {
return Future.failedFuture(new ApiException(message, throwable, code, responseHeaders, responseBody));
}
public static <T> AsyncResult<T> fail(String message, int code, MultiMap responseHeaders, String responseBody) {
return Future.failedFuture(new ApiException(message, (Throwable) null, code, responseHeaders, responseBody));
}
public static <T> AsyncResult<T> fail(int code, MultiMap responseHeaders, String responseBody) {
return Future.failedFuture(new ApiException((String) null, (Throwable) null, code, responseHeaders, responseBody));
}
public ApiException() {}
public ApiException(Throwable throwable) {
super(throwable);
}
public ApiException(String message) {
super(message);
}
public ApiException(String message, Throwable throwable, int code, MultiMap responseHeaders, String responseBody) {
super(message, throwable);
this.code = code;
this.responseHeaders = responseHeaders;
this.responseBody = responseBody;
}
public ApiException(String message, int code, MultiMap responseHeaders, String responseBody) {
this(message, (Throwable) null, code, responseHeaders, responseBody);
}
public ApiException(String message, Throwable throwable, int code, MultiMap responseHeaders) {
this(message, throwable, code, responseHeaders, null);
}
public ApiException(int code, MultiMap responseHeaders, String responseBody) {
this((String) null, (Throwable) null, code, responseHeaders, responseBody);
}
public ApiException(int code, String message) {
super(message);
this.code = code;
}
public ApiException(int code, String message, MultiMap responseHeaders, String responseBody) {
this(code, message);
this.responseHeaders = responseHeaders;
this.responseBody = responseBody;
}
/**
* Get the HTTP status code.
*
* @return HTTP status code
*/
public int getCode() {
return code;
}
/**
* Get the HTTP response headers.
*
* @return A map of list of string
*/
public MultiMap getResponseHeaders() {
return responseHeaders;
}
/**
* Get the HTTP response body.
*
* @return Response body in the form of string
*/
public String getResponseBody() {
return responseBody;
}
}
@@ -0,0 +1,91 @@
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.json.JsonObject;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.*;
import {{invokerPackage}}.ApiClient;
import {{invokerPackage}}.ApiException;
import {{invokerPackage}}.Configuration;
import {{invokerPackage}}.Pair;
{{>generatedAnnotation}}
{{#operations}}
public class {{classname}}Impl implements {{classname}} {
private ApiClient {{localVariablePrefix}}apiClient;
public {{classname}}Impl() {
this(null);
}
public {{classname}}Impl(ApiClient apiClient) {
this.{{localVariablePrefix}}apiClient = apiClient != null ? apiClient : Configuration.getDefaultApiClient();
}
public ApiClient getApiClient() {
return {{localVariablePrefix}}apiClient;
}
public void setApiClient(ApiClient apiClient) {
this.{{localVariablePrefix}}apiClient = apiClient;
}
{{#operation}}
/**
* {{summary}}
* {{notes}}
{{#allParams}}
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
{{/allParams}}
* @param resultHandler Asynchronous result handler
*/
public void {{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}Handler<AsyncResult<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>> resultHandler) {
Object {{localVariablePrefix}}localVarBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
{{#allParams}}{{#required}}
// verify the required parameter '{{paramName}}' is set
if ({{paramName}} == null) {
resultHandler.handle(ApiException.fail(400, "Missing the required parameter '{{paramName}}' when calling {{operationId}}"));
return;
}
{{/required}}{{/allParams}}
// create path and map variables
String {{localVariablePrefix}}localVarPath = "{{{path}}}"{{#pathParams}}.replaceAll("\\{" + "{{baseName}}" + "\\}", {{{paramName}}}.toString()){{/pathParams}};
// query params
List<Pair> {{localVariablePrefix}}localVarQueryParams = new ArrayList<>();
{{#queryParams}}
{{localVariablePrefix}}localVarQueryParams.addAll({{localVariablePrefix}}apiClient.parameterToPairs("{{#collectionFormat}}{{{collectionFormat}}}{{/collectionFormat}}", "{{baseName}}", {{paramName}}));
{{/queryParams}}
// header params
MultiMap {{localVariablePrefix}}localVarHeaderParams = MultiMap.caseInsensitiveMultiMap();
{{#headerParams}}if ({{paramName}} != null)
{{localVariablePrefix}}localVarHeaderParams.add("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}}));
{{/headerParams}}
// form params
// TODO: sending files within multipart/form-data is not supported yet (because of vertx web-client)
Map<String, Object> {{localVariablePrefix}}localVarFormParams = new HashMap<>();
{{#formParams}}if ({{paramName}} != null) {{localVariablePrefix}}localVarFormParams.put("{{baseName}}", {{paramName}});
{{/formParams}}
String[] {{localVariablePrefix}}localVarAccepts = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} };
String[] {{localVariablePrefix}}localVarContentTypes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} };
String[] {{localVariablePrefix}}localVarAuthNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} };
{{#returnType}}
TypeReference<{{{returnType}}}> {{localVariablePrefix}}localVarReturnType = new TypeReference<{{{returnType}}}>() {};
{{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccepts, {{localVariablePrefix}}localVarContentTypes, {{localVariablePrefix}}localVarAuthNames, {{localVariablePrefix}}localVarReturnType, resultHandler);{{/returnType}}{{^returnType}}
{{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccepts, {{localVariablePrefix}}localVarContentTypes, {{localVariablePrefix}}localVarAuthNames, null, resultHandler);{{/returnType}}
}
{{/operation}}
}
{{/operations}}
@@ -0,0 +1,70 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import {{invokerPackage}}.Configuration;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.runner.RunWith;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.core.Vertx;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import io.vertx.ext.unit.junit.RunTestOnContext;
import io.vertx.ext.unit.TestContext;
import io.vertx.ext.unit.Async;
{{^fullJavaUtil}}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
{{/fullJavaUtil}}
/**
* API tests for {{classname}}
*/
@RunWith(VertxUnitRunner.class)
@Ignore
public class {{classname}}Test {
private {{classname}} api;
@Rule
public RunTestOnContext rule = new RunTestOnContext();
@BeforeClass
public void setupApiClient() {
JsonObject config = new JsonObject();
Vertx vertx = rule.vertx();
Configuration.setupDefaultApiClient(vertx, config);
api = new {{classname}}Impl();
}
{{#operations}}{{#operation}}
/**
* {{summary}}
* {{notes}}
*
* @param context Vertx test context for doing assertions
*/
@Test
public void {{operationId}}Test(TestContext context) {
Async async = context.async();
{{#allParams}}
{{{dataType}}} {{paramName}} = null;
{{/allParams}}
api.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}}result -> {
// TODO: test validations
async.complete();
});
}
{{/operation}}{{/operations}}
}
@@ -0,0 +1,64 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import io.vertx.core.MultiMap;
import java.util.List;
{{>generatedAnnotation}}
public class ApiKeyAuth implements Authentication {
private final String location;
private final String paramName;
private String apiKey;
private String apiKeyPrefix;
public ApiKeyAuth(String location, String paramName) {
this.location = location;
this.paramName = paramName;
}
public String getLocation() {
return location;
}
public String getParamName() {
return paramName;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getApiKeyPrefix() {
return apiKeyPrefix;
}
public void setApiKeyPrefix(String apiKeyPrefix) {
this.apiKeyPrefix = apiKeyPrefix;
}
@Override
public void applyToParams(List<Pair> queryParams, MultiMap headerParams) {
if (apiKey == null) {
return;
}
String value;
if (apiKeyPrefix != null) {
value = apiKeyPrefix + " " + apiKey;
} else {
value = apiKey;
}
if ("query".equals(location)) {
queryParams.add(new Pair(paramName, value));
} else if ("header".equals(location)) {
headerParams.add(paramName, value);
}
}
}
@@ -0,0 +1,18 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import io.vertx.core.MultiMap;
import java.util.List;
public interface Authentication {
/**
* Apply authentication settings to header and query params.
*
* @param queryParams List of query parameters
* @param headerParams Map of header parameters
*/
void applyToParams(List<Pair> queryParams, MultiMap headerParams);
}
@@ -0,0 +1,40 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import io.vertx.core.MultiMap;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.util.List;
{{>generatedAnnotation}}
public class HttpBasicAuth implements Authentication {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public void applyToParams(List<Pair> queryParams, MultiMap headerParams) {
if (username == null && password == null) {
return;
}
String str = (username == null ? "" : username) + ":" + (password == null ? "" : password);
headerParams.add("Authorization", "Basic " + Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8)));
}
}
@@ -0,0 +1,28 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import io.vertx.core.MultiMap;
import java.util.List;
{{>generatedAnnotation}}
public class OAuth implements Authentication {
private String accessToken;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
@Override
public void applyToParams(List<Pair> queryParams, MultiMap headerParams) {
if (accessToken != null) {
headerParams.add("Authorization", "Bearer " + accessToken);
}
}
}
@@ -0,0 +1,7 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
public enum OAuthFlow {
accessCode, implicit, password, application
}
@@ -0,0 +1,53 @@
apply plugin: 'idea'
apply plugin: 'eclipse'
group = '{{groupId}}'
version = '{{artifactVersion}}'
repositories {
jcenter()
}
apply plugin: 'java'
apply plugin: 'maven'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
install {
repositories.mavenInstaller {
pom.artifactId = '{{artifactId}}'
}
}
task execute(type:JavaExec) {
main = System.getProperty('mainClass')
classpath = sourceSets.main.runtimeClasspath
}
ext {
swagger_annotations_version = "1.5.15"
jackson_version = "{{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}"
vertx_version = "3.4.2"
junit_version = "4.12"
}
dependencies {
compile "io.swagger:swagger-annotations:$swagger_annotations_version"
compile "io.vertx:vertx-web-client:$vertx_version"
compile "io.vertx:vertx-rx-java:$vertx_version"
compile "com.fasterxml.jackson.core:jackson-core:$jackson_version"
compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version"
compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
{{#joda}}
compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version"
{{/joda}}
{{#java8}}
compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version"
{{/java8}}
{{#threetenbp}}
compile "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_version"
{{/threetenbp}}
testCompile "junit:junit:$junit_version"
testCompile "io.vertx:vertx-unit:$vertx_version"
}
@@ -0,0 +1,259 @@
<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>
<groupId>{{groupId}}</groupId>
<artifactId>{{artifactId}}</artifactId>
<packaging>jar</packaging>
<name>{{artifactId}}</name>
<version>{{artifactVersion}}</version>
<url>{{artifactUrl}}</url>
<description>{{artifactDescription}}</description>
<scm>
<connection>{{scmConnection}}</connection>
<developerConnection>{{scmDeveloperConnection}}</developerConnection>
<url>{{scmUrl}}</url>
</scm>
<prerequisites>
<maven>2.2.0</maven>
</prerequisites>
<licenses>
<license>
<name>{{licenseName}}</name>
<url>{{licenseUrl}}</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>{{developerName}}</name>
<email>{{developerEmail}}</email>
<organization>{{developerOrganization}}</organization>
<organizationUrl>{{developerOrganizationUrl}}</organizationUrl>
</developer>
</developers>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<systemProperties>
<property>
<name>loggerPath</name>
<value>conf/log4j.properties</value>
</property>
</systemProperties>
<argLine>-Xms512m -Xmx1500m</argLine>
<parallel>methods</parallel>
<forkMode>pertest</forkMode>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- attach test jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
<configuration>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>add_sources</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add_test_sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/test/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sign-artifacts</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-core-version}</version>
</dependency>
<!-- Vertx -->
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-rx-java</artifactId>
<version>${vertx-version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>${vertx-version}</version>
</dependency>
<!-- JSON processing: jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-version}</version>
</dependency>
{{#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>
{{/java8}}
{{#threetenbp}}
<dependency>
<groupId>com.github.joschi.jackson</groupId>
<artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-version}</version>
</dependency>
{{/threetenbp}}
<!-- test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-unit</artifactId>
<version>${vertx-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<vertx-version>3.4.2</vertx-version>
<swagger-core-version>1.5.16</swagger-core-version>
<jackson-version>{{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}</jackson-version>
<junit-version>4.12</junit-version>
</properties>
</project>
@@ -0,0 +1,58 @@
package {{package}}.rxjava;
{{#imports}}import {{import}};
{{/imports}}
import java.util.*;
import rx.Single;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
{{>generatedAnnotation}}
{{#operations}}
public class {{classname}} {
private final {{package}}.{{classname}} delegate;
public {{classname}}({{package}}.{{classname}} delegate) {
this.delegate = delegate;
}
public {{package}}.{{classname}} getDelegate() {
return delegate;
}
{{#operation}}
/**
* {{summary}}
* {{notes}}
{{#allParams}}
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
{{/allParams}}
* @param resultHandler Asynchronous result handler
*/
public void {{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}Handler<AsyncResult<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>> resultHandler) {
delegate.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}}resultHandler);
}
/**
* {{summary}}
* {{notes}}
{{#allParams}}
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
{{/allParams}}
* @return Asynchronous result handler (RxJava Single)
*/
public Single<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> rx{{operationIdCamelCase}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) {
return Single.create(new io.vertx.rx.java.SingleOnSubscribeAdapter<>(fut -> {
delegate.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}}fut);
}));
}
{{/operation}}
public static {{classname}} newInstance({{package}}.{{classname}} arg) {
return arg != null ? new {{classname}}(arg) : null;
}
}
{{/operations}}