diff --git a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java index 301feb2d8..96a4706f1 100644 --- a/src/main/java/com/adyen/httpclient/AdyenHttpClient.java +++ b/src/main/java/com/adyen/httpclient/AdyenHttpClient.java @@ -60,6 +60,7 @@ import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.ByteArrayEntity; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.net.URIBuilder; import org.apache.hc.core5.ssl.SSLContexts; @@ -212,6 +213,30 @@ public String request( return response.getBody(); } + @Override + public String requestBinary( + String endpoint, + BinaryRequestBody requestBody, + Config config, + boolean isApiKeyRequired, + RequestOptions requestOptions, + ApiConstants.HttpMethod httpMethod, + Map params) + throws IOException, HTTPClientException { + CloseableHttpClient httpclient = getOrCreateHttpClient(config); + HttpUriRequestBase httpRequest = + createRequest( + endpoint, requestBody, config, isApiKeyRequired, requestOptions, httpMethod, params); + + AdyenResponse response = httpclient.execute(httpRequest, new AdyenResponseHandler()); + + if (response.getStatus() < 200 || response.getStatus() >= 300) { + throw new HTTPClientException( + response.getStatus(), "HTTP Exception", response.getHeaders(), response.getBody()); + } + return response.getBody(); + } + /** * Builds an {@link HttpUriRequestBase} with the appropriate HTTP method, headers, authentication, * and per-request timeout configuration from {@link Config}. @@ -256,15 +281,56 @@ HttpUriRequestBase createRequest( httpRequest.setConfig(builder.build()); setAuthentication(httpRequest, isApiKeyRequired, config); - setHeaders(config, requestOptions, httpRequest); + setHeaders(config, requestOptions, httpRequest, null); return httpRequest; } - private void setHeaders( - Config config, RequestOptions requestOptions, HttpUriRequestBase httpUriRequest) { + HttpUriRequestBase createRequest( + String endpoint, + BinaryRequestBody requestBody, + Config config, + boolean isApiKeyRequired, + RequestOptions requestOptions, + ApiConstants.HttpMethod httpMethod, + Map params) + throws HTTPClientException { + HttpUriRequestBase httpRequest = + createHttpRequestBase(createUri(endpoint, params), requestBody.getData(), httpMethod); + + RequestConfig.Builder builder = RequestConfig.custom(); + builder.setResponseTimeout(config.getReadTimeoutMillis(), TimeUnit.MILLISECONDS); + builder.setConnectTimeout(config.getConnectionTimeoutMillis(), TimeUnit.MILLISECONDS); + builder.setDefaultKeepAlive(config.getDefaultKeepAliveMillis(), TimeUnit.MILLISECONDS); + builder.setConnectionRequestTimeout( + config.getConnectionRequestTimeoutMillis(), TimeUnit.MILLISECONDS); - setContentType(httpUriRequest, APPLICATION_JSON_TYPE); + if (config.getProtocolUpgradeEnabled() != null) { + builder.setProtocolUpgradeEnabled(config.getProtocolUpgradeEnabled()); + } + if (proxy != null && proxy.address() instanceof InetSocketAddress) { + InetSocketAddress inetSocketAddress = (InetSocketAddress) proxy.address(); + builder.setProxy(new HttpHost(inetSocketAddress.getHostName(), inetSocketAddress.getPort())); + } + httpRequest.setConfig(builder.build()); + + setAuthentication(httpRequest, isApiKeyRequired, config); + setHeaders(config, requestOptions, httpRequest, requestBody.getContentType()); + + return httpRequest; + } + + private void setHeaders( + Config config, + RequestOptions requestOptions, + HttpUriRequestBase httpUriRequest, + String requestContentType) { + + String contentType = + requestContentType != null + ? requestContentType + : getAdditionalHeader(requestOptions, CONTENT_TYPE, APPLICATION_JSON_TYPE); + setContentType(httpUriRequest, contentType); httpUriRequest.addHeader(ACCEPT_CHARSET, CHARSET); String applicationName = config.getApplicationName(); @@ -292,11 +358,32 @@ private void setHeaders( } if (requestOptions.getAdditionalServiceHeaders() != null) { - requestOptions.getAdditionalServiceHeaders().forEach(httpUriRequest::addHeader); + requestOptions + .getAdditionalServiceHeaders() + .forEach( + (name, value) -> { + if (!name.equalsIgnoreCase(CONTENT_TYPE) + && (requestContentType == null || !name.equalsIgnoreCase("Content-Length"))) { + httpUriRequest.addHeader(name, value); + } + }); } } } + private String getAdditionalHeader( + RequestOptions requestOptions, String name, String defaultValue) { + if (requestOptions != null && requestOptions.getAdditionalServiceHeaders() != null) { + for (Map.Entry header : + requestOptions.getAdditionalServiceHeaders().entrySet()) { + if (header.getKey().equalsIgnoreCase(name)) { + return header.getValue(); + } + } + } + return defaultValue; + } + private HttpUriRequestBase createHttpRequestBase( URI endpoint, String requestBody, ApiConstants.HttpMethod httpMethod) { StringEntity requestEntity = null; @@ -321,6 +408,27 @@ private HttpUriRequestBase createHttpRequestBase( } } + private HttpUriRequestBase createHttpRequestBase( + URI endpoint, byte[] requestBody, ApiConstants.HttpMethod httpMethod) { + ByteArrayEntity requestEntity = + requestBody == null ? null : new ByteArrayEntity(requestBody, null); + + switch (httpMethod) { + case GET: + return new HttpGet(endpoint); + case PATCH: + HttpPatch httpPatch = new HttpPatch(endpoint); + httpPatch.setEntity(requestEntity); + return httpPatch; + case DELETE: + return new HttpDelete(endpoint); + default: + HttpPost httpPost = new HttpPost(endpoint); + httpPost.setEntity(requestEntity); + return httpPost; + } + } + private URI createUri(String endpoint, Map params) throws HTTPClientException { try { URIBuilder uriBuilder = new URIBuilder(endpoint); @@ -406,7 +514,7 @@ private void setAuthentication( /** Sets the Content-Type header on the request. */ private void setContentType(HttpUriRequest httpUriRequest, String contentType) { - httpUriRequest.addHeader(CONTENT_TYPE, contentType); + httpUriRequest.setHeader(CONTENT_TYPE, contentType); } /** Sets the X-API-Key header on the request. */ diff --git a/src/main/java/com/adyen/httpclient/BinaryRequestBody.java b/src/main/java/com/adyen/httpclient/BinaryRequestBody.java new file mode 100644 index 000000000..e410b4b9b --- /dev/null +++ b/src/main/java/com/adyen/httpclient/BinaryRequestBody.java @@ -0,0 +1,58 @@ +/* + * ###### + * ###### + * ############ ####( ###### #####. ###### ############ ############ + * ############# #####( ###### #####. ###### ############# ############# + * ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + * ############# ############# ############# ############# ##### ###### + * ############ ############ ############# ############# ###### + * ###### + * ############# + * ############ + * + * Adyen Java API Library + * + * Copyright (c) 2026 Adyen B.V. + * This file is open source and available under the MIT license. + * See the LICENSE file for more info. + */ +package com.adyen.httpclient; + +import java.util.Arrays; + +/** Contains a binary request payload and its content type. */ +public final class BinaryRequestBody { + private final byte[] data; + private final String contentType; + + /** + * Creates a binary request payload. + * + * @param data request body data + * @param contentType request content type + */ + public BinaryRequestBody(byte[] data, String contentType) { + this.data = Arrays.copyOf(data, data.length); + this.contentType = contentType; + } + + /** + * Gets a copy of the request body data. + * + * @return request body data + */ + public byte[] getData() { + return Arrays.copyOf(data, data.length); + } + + /** + * Gets the request content type. + * + * @return request content type + */ + public String getContentType() { + return contentType; + } +} diff --git a/src/main/java/com/adyen/httpclient/ClientInterface.java b/src/main/java/com/adyen/httpclient/ClientInterface.java index 5ff43e387..1204aaa13 100644 --- a/src/main/java/com/adyen/httpclient/ClientInterface.java +++ b/src/main/java/com/adyen/httpclient/ClientInterface.java @@ -136,4 +136,32 @@ String request( ApiConstants.HttpMethod httpMethod, Map params) throws IOException, HTTPClientException; + + /** + * Sends a binary HTTP request. Custom HTTP client implementations must override this method to + * support multipart API operations. + * + * @param endpoint the full URL of the API endpoint + * @param requestBody the binary request body and its content type + * @param config the client configuration + * @param isApiKeyRequired whether API key authentication is mandatory + * @param requestOptions additional request options (idempotency key, custom headers) + * @param httpMethod the HTTP method + * @param params query string parameters appended to the URL + * @return the response body + * @throws IOException if a network error occurs + * @throws HTTPClientException if the server returns a non-2xx status code + */ + default String requestBinary( + String endpoint, + BinaryRequestBody requestBody, + Config config, + boolean isApiKeyRequired, + RequestOptions requestOptions, + ApiConstants.HttpMethod httpMethod, + Map params) + throws IOException, HTTPClientException { + throw new UnsupportedOperationException( + "The configured HTTP client does not support binary request bodies"); + } } diff --git a/src/main/java/com/adyen/httpclient/HttpFile.java b/src/main/java/com/adyen/httpclient/HttpFile.java new file mode 100644 index 000000000..d81b8d9fe --- /dev/null +++ b/src/main/java/com/adyen/httpclient/HttpFile.java @@ -0,0 +1,58 @@ +/* + * ###### + * ###### + * ############ ####( ###### #####. ###### ############ ############ + * ############# #####( ###### #####. ###### ############# ############# + * ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + * ############# ############# ############# ############# ##### ###### + * ############ ############ ############# ############# ###### + * ###### + * ############# + * ############ + * + * Adyen Java API Library + * + * Copyright (c) 2026 Adyen B.V. + * This file is open source and available under the MIT license. + * See the LICENSE file for more info. + */ +package com.adyen.httpclient; + +import java.util.Arrays; + +/** Represents a file uploaded as part of a multipart request. */ +public class HttpFile { + private final byte[] data; + private final String name; + + /** + * Creates a file for a multipart request. + * + * @param data file contents + * @param name file name sent to the API + */ + public HttpFile(byte[] data, String name) { + this.data = Arrays.copyOf(data, data.length); + this.name = name; + } + + /** + * Gets a copy of the file contents. + * + * @return file contents + */ + public byte[] getData() { + return Arrays.copyOf(data, data.length); + } + + /** + * Gets the file name. + * + * @return file name + */ + public String getName() { + return name; + } +} diff --git a/src/main/java/com/adyen/httpclient/RequestForm.java b/src/main/java/com/adyen/httpclient/RequestForm.java new file mode 100644 index 000000000..cb6d9c707 --- /dev/null +++ b/src/main/java/com/adyen/httpclient/RequestForm.java @@ -0,0 +1,138 @@ +/* + * ###### + * ###### + * ############ ####( ###### #####( ###### ############ ############ + * ############# #####( ###### #####. ###### ############# ############# + * ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ###### ##### ###### + * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + * ############# ############# ############# ############# ##### ###### + * ############ ############ ############# ############# ###### + * ###### + * ############# + * ############ + * + * Adyen Java API Library + * + * Copyright (c) 2026 Adyen B.V. + * This file is open source and available under the MIT license. + * See the LICENSE file for more info. + */ +package com.adyen.httpclient; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.net.URLEncodedUtils; + +/** Serializes multipart and URL-encoded request form data. */ +public final class RequestForm { + private static final String MULTIPART_FORM_DATA = "multipart/form-data"; + private static final String URL_ENCODED_FORM_DATA = "application/x-www-form-urlencoded"; + + private final boolean multipart; + private final List urlEncodedFields = new ArrayList<>(); + private final MultipartEntityBuilder multipartBuilder; + private HttpEntity multipartEntity; + + private RequestForm(boolean multipart) { + this.multipart = multipart; + this.multipartBuilder = multipart ? MultipartEntityBuilder.create() : null; + } + + /** + * Creates a form encoder for an operation's supported content types. + * + * @param contentTypes media types accepted by the operation + * @return a multipart or URL-encoded form encoder + */ + public static RequestForm create(List contentTypes) { + boolean isMultipart = + contentTypes.stream() + .map(RequestForm::normalizeMediaType) + .anyMatch(MULTIPART_FORM_DATA::equals); + return new RequestForm(isMultipart); + } + + /** + * Adds a text form field. + * + * @param name field name + * @param value field value + */ + public void add(String name, String value) { + if (multipart) { + multipartBuilder.addTextBody(name, value, ContentType.TEXT_PLAIN); + } else { + urlEncodedFields.add(new BasicNameValuePair(name, value)); + } + } + + /** + * Adds a file form field. + * + * @param name field name + * @param file file value + * @throws IllegalStateException if the operation does not accept multipart form data + */ + public void add(String name, HttpFile file) { + if (!multipart) { + throw new IllegalStateException("Files require a multipart/form-data request"); + } + multipartBuilder.addBinaryBody( + name, file.getData(), ContentType.DEFAULT_BINARY, file.getName()); + } + + /** + * Serializes the form request body. + * + * @return encoded request body + * @throws IOException if multipart serialization fails + */ + public byte[] getRequestBody() throws IOException { + if (!multipart) { + return URLEncodedUtils.format(urlEncodedFields, StandardCharsets.UTF_8) + .getBytes(StandardCharsets.UTF_8); + } + + HttpEntity entity = getMultipartEntity(); + try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { + entity.writeTo(output); + return output.toByteArray(); + } + } + + /** + * Gets the request content type, including its multipart boundary where applicable. + * + * @return form content type + */ + public String getContentType() { + if (!multipart) { + return URL_ENCODED_FORM_DATA; + } + return getMultipartEntity().getContentType(); + } + + private static String normalizeMediaType(String contentType) { + int parameterIndex = contentType.indexOf(';'); + return contentType + .substring(0, parameterIndex < 0 ? contentType.length() : parameterIndex) + .trim() + .toLowerCase(); + } + + private HttpEntity getMultipartEntity() { + if (multipartEntity == null) { + multipartEntity = multipartBuilder.build(); + } + return multipartEntity; + } +} diff --git a/src/main/java/com/adyen/service/resource/Resource.java b/src/main/java/com/adyen/service/resource/Resource.java index edb1619c4..b1cb55131 100644 --- a/src/main/java/com/adyen/service/resource/Resource.java +++ b/src/main/java/com/adyen/service/resource/Resource.java @@ -25,6 +25,7 @@ import com.adyen.Config; import com.adyen.Service; import com.adyen.constants.ApiConstants; +import com.adyen.httpclient.BinaryRequestBody; import com.adyen.httpclient.ClientInterface; import com.adyen.httpclient.HTTPClientException; import com.adyen.model.ApiError; @@ -145,6 +146,55 @@ public String request( throw apiException; } + /** + * Sends a binary request body. + * + * @param body request body + * @param contentType request content type + * @param requestOptions request options + * @param httpMethod HTTP method + * @param pathParams path parameters + * @param queryString query string parameters + * @return response body + * @throws ApiException when an API error is returned + * @throws IOException when an unexpected error occurs + */ + public String request( + byte[] body, + String contentType, + RequestOptions requestOptions, + ApiConstants.HttpMethod httpMethod, + Map pathParams, + Map queryString) + throws ApiException, IOException { + ClientInterface clientInterface = service.getClient().getHttpClient(); + Config config = service.getClient().getConfig(); + ApiException apiException; + try { + return clientInterface.requestBinary( + resolve(pathParams), + new BinaryRequestBody(body, contentType), + config, + service.isApiKeyRequired(), + requestOptions, + httpMethod, + queryString); + } catch (HTTPClientException e) { + try { + ApiError apiError = ApiError.fromJson(e.getResponseBody()); + String message = apiError.getMessage() + " ErrorCode: " + apiError.getErrorCode(); + + apiException = new ApiException(message, e.getCode(), e.getResponseHeaders()); + apiException.setResponseBody(e.getResponseBody()); + apiException.setError(apiError); + } catch (Exception ignore) { + apiException = new ApiException(e.getMessage(), e.getCode(), e.getResponseHeaders()); + apiException.setResponseBody(e.getResponseBody()); + } + } + throw apiException; + } + private String resolve(Map params) { if (endpoint == null || params == null || endpoint.isEmpty() || params.isEmpty()) { return endpoint; diff --git a/src/test/java/com/adyen/httpclient/ClientTest.java b/src/test/java/com/adyen/httpclient/ClientTest.java index 919ff9aad..01a07bf27 100644 --- a/src/test/java/com/adyen/httpclient/ClientTest.java +++ b/src/test/java/com/adyen/httpclient/ClientTest.java @@ -276,6 +276,33 @@ public void testRequestWithHttpHeaders() throws Exception { assertEquals("www-authenticate-header", wwwAuthenticate.getValue()); } + @Test + public void testBinaryRequestPreservesMultipartContentType() throws Exception { + AdyenHttpClient client = new AdyenHttpClient(); + HashMap additionalHeaders = new HashMap<>(); + additionalHeaders.put("content-type", "application/json"); + additionalHeaders.put("Content-Length", "1"); + additionalHeaders.put("X-Custom-Header", "custom-value"); + + HttpUriRequestBase request = + client.createRequest( + "https://checkout-test.adyen.com/v68/documents", + new BinaryRequestBody( + "multipart body".getBytes(), "multipart/form-data; boundary=example-boundary"), + new Config(), + true, + new RequestOptions().additionalServiceHeaders(additionalHeaders), + ApiConstants.HttpMethod.POST, + Map.of()); + + Header contentType = request.getFirstHeader("Content-Type"); + assertNotNull(contentType); + assertEquals("multipart/form-data; boundary=example-boundary", contentType.getValue()); + assertEquals(1, request.getHeaders("Content-Type").length); + assertNull(request.getFirstHeader("Content-Length")); + assertEquals("custom-value", request.getFirstHeader("X-Custom-Header").getValue()); + } + @Test public void testGetHttpClientReturnsSameInstance() { Client client = new Client("apiKey", Environment.TEST); diff --git a/src/test/java/com/adyen/httpclient/RequestFormTest.java b/src/test/java/com/adyen/httpclient/RequestFormTest.java new file mode 100644 index 000000000..bd4086036 --- /dev/null +++ b/src/test/java/com/adyen/httpclient/RequestFormTest.java @@ -0,0 +1,46 @@ +package com.adyen.httpclient; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RequestFormTest { + + @Test + void serializesUrlEncodedFields() throws Exception { + RequestForm form = RequestForm.create(List.of("application/x-www-form-urlencoded")); + form.add("description", "a value & more"); + + assertEquals("application/x-www-form-urlencoded", form.getContentType()); + assertEquals( + "description=a+value+%26+more", new String(form.getRequestBody(), StandardCharsets.UTF_8)); + } + + @Test + void serializesMultipartFilesAndFields() throws Exception { + RequestForm form = RequestForm.create(List.of("multipart/form-data; charset=utf-8")); + form.add("description", "test file"); + form.add("file", new HttpFile("file data".getBytes(StandardCharsets.UTF_8), "test.txt")); + + String requestBody = new String(form.getRequestBody(), StandardCharsets.UTF_8); + assertTrue(form.getContentType().startsWith("multipart/form-data")); + assertTrue(form.getContentType().contains("boundary=")); + assertTrue(requestBody.contains("name=\"description\"")); + assertTrue(requestBody.contains("test file")); + assertTrue(requestBody.contains("filename=\"test.txt\"")); + assertTrue(requestBody.contains("file data")); + } + + @Test + void rejectsFilesForUrlEncodedRequests() { + RequestForm form = RequestForm.create(List.of("application/x-www-form-urlencoded")); + + assertThrows( + IllegalStateException.class, + () -> form.add("file", new HttpFile(new byte[] {1}, "test.bin"))); + } +} diff --git a/templates-v7/libraries/jersey3/api.mustache b/templates-v7/libraries/jersey3/api.mustache index cd0aa898c..b20225202 100644 --- a/templates-v7/libraries/jersey3/api.mustache +++ b/templates-v7/libraries/jersey3/api.mustache @@ -9,8 +9,14 @@ import com.adyen.constants.ApiConstants; import com.adyen.model.RequestOptions; import com.adyen.service.exception.ApiException; import com.adyen.service.resource.Resource; +{{#hasFormParams}} +import com.adyen.httpclient.RequestForm; +{{/hasFormParams}} import java.io.IOException; +{{#hasFormParams}} +import java.util.Arrays; +{{/hasFormParams}} import java.util.HashMap; import java.util.Map; import java.util.List; @@ -78,14 +84,37 @@ public class {{classname}} extends Service { {{/queryParams}} {{/hasQueryParams}} + {{#formParams}} + {{#required}} + if ({{paramName}} == null) { + throw new IllegalArgumentException("Please provide the {{paramName}} form parameter"); + } + {{/required}} + {{/formParams}} String requestBody = {{#bodyParam}}{{paramName}}.toJson(){{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + {{#hasFormParams}} + RequestForm form = RequestForm.create(Arrays.asList({{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}})); + {{#formParams}} + if ({{paramName}} != null) { + {{#isArray}} + for (Object element : {{paramName}}) { + form.add("{{baseName}}", {{#isFile}}(com.adyen.httpclient.HttpFile) element{{/isFile}}{{^isFile}}String.valueOf(element){{/isFile}}); + } + {{/isArray}} + {{^isArray}} + form.add("{{baseName}}", {{#isFile}}{{paramName}}{{/isFile}}{{^isFile}}String.valueOf({{paramName}}){{/isFile}}); + {{/isArray}} + } + {{/formParams}} + byte[] formRequestBody = form.getRequestBody(); + {{/hasFormParams}} Resource resource = new Resource(this, this.baseURL + "{{{path}}}", null); {{#returnType}} - String jsonResult = resource.request(requestBody, requestOptions, ApiConstants.HttpMethod.{{httpMethod}}, {{#hasPathParams}}pathParams{{/hasPathParams}}{{^hasPathParams}}null{{/hasPathParams}}{{#hasQueryParams}}, queryParams{{/hasQueryParams}}); + String jsonResult = {{#hasFormParams}}resource.request(formRequestBody, form.getContentType(), requestOptions, ApiConstants.HttpMethod.{{httpMethod}}, {{#hasPathParams}}pathParams{{/hasPathParams}}{{^hasPathParams}}null{{/hasPathParams}}, {{#hasQueryParams}}queryParams{{/hasQueryParams}}{{^hasQueryParams}}null{{/hasQueryParams}}){{/hasFormParams}}{{^hasFormParams}}resource.request(requestBody, requestOptions, ApiConstants.HttpMethod.{{httpMethod}}, {{#hasPathParams}}pathParams{{/hasPathParams}}{{^hasPathParams}}null{{/hasPathParams}}{{#hasQueryParams}}, queryParams{{/hasQueryParams}}){{/hasFormParams}}; return {{#returnType}}{{{.}}}.fromJson(jsonResult){{/returnType}}; {{/returnType}} {{^returnType}} - resource.request(requestBody, requestOptions, ApiConstants.HttpMethod.{{httpMethod}}, {{#hasPathParams}}pathParams{{/hasPathParams}}{{^hasPathParams}}null{{/hasPathParams}}{{#hasQueryParams}}, queryParams{{/hasQueryParams}}); + {{#hasFormParams}}resource.request(formRequestBody, form.getContentType(), requestOptions, ApiConstants.HttpMethod.{{httpMethod}}, {{#hasPathParams}}pathParams{{/hasPathParams}}{{^hasPathParams}}null{{/hasPathParams}}, {{#hasQueryParams}}queryParams{{/hasQueryParams}}{{^hasQueryParams}}null{{/hasQueryParams}});{{/hasFormParams}}{{^hasFormParams}}resource.request(requestBody, requestOptions, ApiConstants.HttpMethod.{{httpMethod}}, {{#hasPathParams}}pathParams{{/hasPathParams}}{{^hasPathParams}}null{{/hasPathParams}}{{#hasQueryParams}}, queryParams{{/hasQueryParams}});{{/hasFormParams}} {{/returnType}} } {{/operation}} diff --git a/templates-v7/libraries/jersey3/api_overload.mustache b/templates-v7/libraries/jersey3/api_overload.mustache index e5615b7a2..10ba2b685 100644 --- a/templates-v7/libraries/jersey3/api_overload.mustache +++ b/templates-v7/libraries/jersey3/api_overload.mustache @@ -1,3 +1,3 @@ {{! Overload contains just required and body params }} -{{#requiredParams}}{{^isHeaderParam}}{{^isBodyParam}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{#-last}}{{#hasBodyParam}}, {{/hasBodyParam}}{{/-last}}{{/isBodyParam}}{{/isHeaderParam}} +{{#requiredParams}}{{^isHeaderParam}}{{^isBodyParam}}{{#isFile}}{{#isArray}}java.util.List{{/isArray}}{{^isArray}}com.adyen.httpclient.HttpFile{{/isArray}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{#-last}}{{#hasBodyParam}}, {{/hasBodyParam}}{{/-last}}{{/isBodyParam}}{{/isHeaderParam}} {{/requiredParams}}{{#bodyParams}}{{{dataType}}} {{paramName}}{{/bodyParams}} \ No newline at end of file diff --git a/templates-v7/libraries/jersey3/api_overload_invoke.mustache b/templates-v7/libraries/jersey3/api_overload_invoke.mustache index 52479b036..ae789a4c1 100644 --- a/templates-v7/libraries/jersey3/api_overload_invoke.mustache +++ b/templates-v7/libraries/jersey3/api_overload_invoke.mustache @@ -1,2 +1,2 @@ {{! Overload contains just required and body params, null on the remaining }} -{{#pathParams}}{{paramName}}, {{/pathParams}}{{#queryParams}}{{#required}}{{paramName}}, {{/required}}{{^required}}null, {{/required}} {{/queryParams}}{{#bodyParams}}{{paramName}}, {{/bodyParams}}null \ No newline at end of file +{{#pathParams}}{{paramName}}, {{/pathParams}}{{#queryParams}}{{#required}}{{paramName}}, {{/required}}{{^required}}null, {{/required}} {{/queryParams}}{{#bodyParams}}{{paramName}}, {{/bodyParams}}{{#formParams}}{{#required}}{{paramName}}, {{/required}}{{^required}}null, {{/required}}{{/formParams}}null \ No newline at end of file diff --git a/templates-v7/libraries/jersey3/api_parameters.mustache b/templates-v7/libraries/jersey3/api_parameters.mustache index 4214551d2..20bdb6a81 100644 --- a/templates-v7/libraries/jersey3/api_parameters.mustache +++ b/templates-v7/libraries/jersey3/api_parameters.mustache @@ -1,2 +1,2 @@ -{{! Path and body are required, followed by optional query string and request options }} -{{#pathParams}}{{{dataType}}} {{paramName}}, {{/pathParams}}{{#queryParams}}{{{dataType}}} {{paramName}}, {{/queryParams}}{{#bodyParams}}{{{dataType}}} {{paramName}}, {{/bodyParams}}RequestOptions requestOptions \ No newline at end of file +{{! Path and body are required, followed by form and query string parameters, then request options }} +{{#pathParams}}{{{dataType}}} {{paramName}}, {{/pathParams}}{{#queryParams}}{{{dataType}}} {{paramName}}, {{/queryParams}}{{#bodyParams}}{{{dataType}}} {{paramName}}, {{/bodyParams}}{{#formParams}}{{#isFile}}{{#isArray}}java.util.List{{/isArray}}{{^isArray}}com.adyen.httpclient.HttpFile{{/isArray}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}, {{/formParams}}RequestOptions requestOptions \ No newline at end of file diff --git a/templates-v7/libraries/jersey3/api_summary.mustache b/templates-v7/libraries/jersey3/api_summary.mustache index 284fd96b4..53f3e8c00 100644 --- a/templates-v7/libraries/jersey3/api_summary.mustache +++ b/templates-v7/libraries/jersey3/api_summary.mustache @@ -7,6 +7,9 @@ {{#bodyParams}} * @param {{paramName}} {{#isContainer}}{@code {{{dataType}}} }{{/isContainer}}{{^isContainer}}{@link {{dataType}} }{{/isContainer}} {{description}} (required) {{/bodyParams}} +{{#formParams}} + * @param {{paramName}} {{#isFile}}{@link com.adyen.httpclient.HttpFile }{{/isFile}}{{^isFile}}{{#isContainer}}{@code {{{dataType}}} }{{/isContainer}}{{^isContainer}}{@link {{dataType}} }{{/isContainer}}{{/isFile}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional){{/required}} +{{/formParams}} {{#queryParams}} * @param {{paramName}} {{#isContainer}}{@code {{{dataType}}} }{{/isContainer}}{{^isContainer}}{@link {{dataType}} }{{/isContainer}} Query: {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/isContainer}}{{/required}} {{/queryParams}}