Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
07d5e9a
New Forward/Secrets module + tests (unit/integration)
david-ruiz-cko Mar 5, 2026
6d583ba
New module network token + test
david-ruiz-cko Mar 5, 2026
ac91466
New module network tokens + tests (unit + integration)
david-ruiz-cko Mar 5, 2026
9cd6534
New module issuing/disputes + unit and integration tests
david-ruiz-cko Mar 6, 2026
afbf787
- Transport headers modification
david-ruiz-cko Mar 9, 2026
d780ab1
RollingReserveRule rename
david-ruiz-cko Mar 9, 2026
07d5c14
New endpoints in AccountsClient for entities file management + unit a…
david-ruiz-cko Mar 10, 2026
f27c2d7
Issuing/transactions read endpoints support + unit and integration tests
david-ruiz-cko Mar 10, 2026
052c5b4
New payments/search endpoint + unit and integration tests
david-ruiz-cko Mar 11, 2026
c6c5cef
- PaymentMethodType generic enum in common.
david-ruiz-cko Mar 11, 2026
6141fc6
Unused import deletion
david-ruiz-cko Mar 11, 2026
ffcd891
StandaloneAccountUpdaterClient initial development (must review)
david-ruiz-cko Mar 12, 2026
5f3a057
Recovered explicit content type header
david-ruiz-cko Mar 16, 2026
1ab1260
Final transport conflict fix
david-ruiz-cko Mar 16, 2026
8268162
StandaloneAccountUpdater + unit + integrations tests
david-ruiz-cko Mar 16, 2026
7e4617a
Applepay module + unit and integration tests
david-ruiz-cko Mar 17, 2026
7aa474f
dummy pull to swap networktokens folder to minor case
david-ruiz-cko Mar 18, 2026
bd49432
networktokens folder to minor case
david-ruiz-cko Mar 18, 2026
186bf4f
PaymentMethod conflict resolution (now in common package)
david-ruiz-cko Mar 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 42 additions & 35 deletions src/main/java/com/checkout/ApacheHttpClientTransport.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.checkout;

import com.checkout.accounts.AccountsFileRequest;
import com.checkout.accounts.Headers;
import com.checkout.common.AbstractFileRequest;
import com.checkout.common.CheckoutUtils;
import com.checkout.common.FileRequest;
Expand Down Expand Up @@ -33,6 +34,7 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand All @@ -42,6 +44,7 @@
import java.util.stream.Collectors;
import java.util.function.Supplier;

import com.google.gson.annotations.SerializedName;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.retry.Retry;
Expand Down Expand Up @@ -99,7 +102,6 @@
final String idempotencyKey,
final Map<String, String> queryParams) {

final Object requestBodyOrEntity = prepareRequestContent(requestObject);
return CompletableFuture.supplyAsync(() -> {
final HttpUriRequest request;
switch (clientOperation) {
Expand Down Expand Up @@ -135,7 +137,7 @@
if (idempotencyKey != null) {
request.setHeader(CKO_IDEMPOTENCY_KEY, idempotencyKey);
}
return performCall(authorization, requestBodyOrEntity, request, clientOperation);
return performCall(authorization, requestObject, request, clientOperation);
}, executor);
}

Expand All @@ -155,7 +157,6 @@
final Object requestObject,
final String idempotencyKey,
final Map<String, String> queryParams) {
final Object requestBodyOrEntity = prepareRequestContent(requestObject);
final HttpUriRequest request;
switch (clientOperation) {
case GET:
Expand Down Expand Up @@ -191,7 +192,7 @@
request.setHeader(CKO_IDEMPOTENCY_KEY, idempotencyKey);
}

final Supplier<Response> callSupplier = () -> performCall(authorization, requestBodyOrEntity, request, clientOperation);
final Supplier<Response> callSupplier = () -> performCall(authorization, requestObject, request, clientOperation);
return executeWithResilience4j(callSupplier);
}

Expand Down Expand Up @@ -235,29 +236,6 @@
return decoratedSupplier.get();
}

/**
* Prepares the request content based on the type of request object.
* If the request object is a UrlEncodedFormEntity, it returns it directly.
* Otherwise, it serializes the object to JSON.
*/
private Object prepareRequestContent(final Object requestObject) {
Object request = null;

if (requestObject != null) {
if (requestObject instanceof UrlEncodedFormEntity) {
// Return the form entity directly for form-encoded requests
request = requestObject;
}
else
{
// Default behavior: serialize to JSON
request = serializer.toJson(requestObject);
}
}

return request;
}

private HttpEntity getMultipartFileEntity(final AbstractFileRequest abstractFileRequest) {
final MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
if (abstractFileRequest instanceof FileRequest) {
Expand All @@ -277,31 +255,43 @@
}

private Response performCall(final SdkAuthorization authorization,
final Object requestBodyOrEntity,
final Object requestBody,
final HttpUriRequest request,
final ClientOperation clientOperation) {
log.info("{}: {}", clientOperation, request.getURI());
request.setHeader(USER_AGENT, PROJECT_NAME + "/" + getVersionFromManifest());
request.setHeader(ACCEPT, getAcceptHeader(clientOperation));
request.setHeader(AUTHORIZATION, authorization.getAuthorizationHeader());

// Check and add headers from the request object if needed
addHeadersFromRequestBody(requestBody, request);

String currentRequestId = UUID.randomUUID().toString();

addTelemetryHeader(request, currentRequestId);

long startTime = System.currentTimeMillis();

log.info("Request: " + Arrays.toString(sanitiseHeaders(request.getAllHeaders())));
if (requestBodyOrEntity != null && request instanceof HttpEntityEnclosingRequest) {
if (requestBodyOrEntity instanceof UrlEncodedFormEntity) {
// Handle form-encoded content
if (requestBody != null && request instanceof HttpEntityEnclosingRequest) {
HttpEntity httpEntity = null;

if (requestBody instanceof HttpEntity) {
httpEntity = (HttpEntity) requestBody;
} else if (requestBody instanceof MultipartEntityBuilder) {
httpEntity = ((MultipartEntityBuilder) requestBody).build();
} else if (requestBody instanceof UrlEncodedFormEntity) {

Check failure

Code scanning / CodeQL

Contradictory type checks Error

This access of
requestBody
cannot be of type
UrlEncodedFormEntity
, since
this expression
ensures that it is not of type
HttpEntity
.
// Ensure proper Content-Type header for form-encoded content
request.setHeader(CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
((HttpEntityEnclosingRequestBase) request).setEntity((UrlEncodedFormEntity) requestBodyOrEntity);
} else if (requestBodyOrEntity instanceof String) {
// Handle JSON content
((HttpEntityEnclosingRequestBase) request).setEntity(new StringEntity((String) requestBodyOrEntity, ContentType.APPLICATION_JSON));
httpEntity = (UrlEncodedFormEntity) requestBody;

Check failure

Code scanning / CodeQL

Contradictory type checks Error

This access of
requestBody
cannot be of type
UrlEncodedFormEntity
, since
this expression
ensures that it is not of type
HttpEntity
.
} else {
String json = serializer.toJson(requestBody);
httpEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
}

((HttpEntityEnclosingRequestBase) request).setEntity(httpEntity);
}

try (final CloseableHttpResponse response = httpClient.execute(request)) {
long elapsed = System.currentTimeMillis() - startTime;
log.info("Response: " + response.getStatusLine().getStatusCode() + " " + Arrays.toString(response.getAllHeaders()));
Expand All @@ -327,6 +317,23 @@
}
}

private void addHeadersFromRequestBody(final Object requestBody, final HttpUriRequest request) {
if (requestBody instanceof Headers) {
Headers headers = (Headers) requestBody;
for (Field field : Headers.class.getDeclaredFields()) {
field.setAccessible(true);
try {
Object value = field.get(headers);
if (value != null && !value.toString().isEmpty()) {
SerializedName serializedName = field.getAnnotation(SerializedName.class);
String headerName = serializedName != null ? serializedName.value() : field.getName();
request.setHeader(headerName, value.toString());
}
} catch (IllegalAccessException ignored) {}

Check warning on line 332 in src/main/java/com/checkout/ApacheHttpClientTransport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this block of code, fill it in, or add a comment explaining why it is empty.

See more on https://sonarcloud.io/project/issues?id=checkout_checkout-sdk-java&issues=AZz7DQ_G3yI2Hoe5mPPl&open=AZz7DQ_G3yI2Hoe5mPPl&pullRequest=554
}
}
}

private void addTelemetryHeader(HttpUriRequest request, String currentRequestId) {
if (configuration.isTelemetryEnabled()) {
String telemetryHeader = generateTelemetryHeader(currentRequestId);
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/checkout/CheckoutApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.checkout.forward.ForwardClient;
import com.checkout.handlepaymentsandpayouts.flow.FlowClient;
import com.checkout.handlepaymentsandpayouts.setups.PaymentSetupsClient;
import com.checkout.handlepaymentsandpayouts.applepay.ApplePayClient;
import com.checkout.identities.faceauthentications.FaceAuthenticationClient;
import com.checkout.identities.applicants.ApplicantClient;
import com.checkout.identities.identityverification.IdentityVerificationClient;
Expand All @@ -17,13 +18,16 @@
import com.checkout.instruments.InstrumentsClient;
import com.checkout.issuing.IssuingClient;
import com.checkout.metadata.MetadataClient;
import com.checkout.networktokens.NetworkTokensClient;
import com.checkout.paymentmethods.PaymentMethodsClient;
import com.checkout.payments.PaymentsClient;
import com.checkout.payments.contexts.PaymentContextsClient;
import com.checkout.payments.hosted.HostedPaymentsClient;
import com.checkout.payments.links.PaymentLinksClient;
import com.checkout.reports.ReportsClient;
import com.checkout.risk.RiskClient;
import com.checkout.sessions.SessionsClient;
import com.checkout.standaloneaccountupdater.StandaloneAccountUpdaterClient;
import com.checkout.tokens.TokensClient;
import com.checkout.transfers.TransfersClient;
import com.checkout.workflows.WorkflowsClient;
Expand Down Expand Up @@ -52,6 +56,8 @@ public interface CheckoutApi extends CheckoutApmApi {

PaymentLinksClient paymentLinksClient();

PaymentMethodsClient paymentMethodsClient();

HostedPaymentsClient hostedPaymentsClient();

BalancesClient balancesClient();
Expand All @@ -72,6 +78,8 @@ public interface CheckoutApi extends CheckoutApmApi {

PaymentSetupsClient paymentSetupsClient();

ApplePayClient applePayClient();

ForwardClient forwardClient();

FaceAuthenticationClient faceAuthenticationClient();
Expand All @@ -84,4 +92,8 @@ public interface CheckoutApi extends CheckoutApmApi {

AmlScreeningClient amlScreeningClient();

NetworkTokensClient networkTokensClient();

StandaloneAccountUpdaterClient standaloneAccountUpdaterClient();

}
30 changes: 30 additions & 0 deletions src/main/java/com/checkout/CheckoutApiImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import com.checkout.handlepaymentsandpayouts.flow.FlowClientImpl;
import com.checkout.handlepaymentsandpayouts.setups.PaymentSetupsClient;
import com.checkout.handlepaymentsandpayouts.setups.PaymentSetupsClientImpl;
import com.checkout.handlepaymentsandpayouts.applepay.ApplePayClient;
import com.checkout.handlepaymentsandpayouts.applepay.ApplePayClientImpl;
import com.checkout.identities.faceauthentications.FaceAuthenticationClient;
import com.checkout.identities.faceauthentications.FaceAuthenticationClientImpl;
import com.checkout.identities.applicants.ApplicantClient;
Expand All @@ -34,6 +36,10 @@
import com.checkout.issuing.IssuingClientImpl;
import com.checkout.metadata.MetadataClient;
import com.checkout.metadata.MetadataClientImpl;
import com.checkout.networktokens.NetworkTokensClient;
import com.checkout.networktokens.NetworkTokensClientImpl;
import com.checkout.paymentmethods.PaymentMethodsClient;
import com.checkout.paymentmethods.PaymentMethodsClientImpl;
import com.checkout.payments.PaymentsClient;
import com.checkout.payments.PaymentsClientImpl;
import com.checkout.payments.contexts.PaymentContextsClient;
Expand All @@ -48,6 +54,8 @@
import com.checkout.risk.RiskClientImpl;
import com.checkout.sessions.SessionsClient;
import com.checkout.sessions.SessionsClientImpl;
import com.checkout.standaloneaccountupdater.StandaloneAccountUpdaterClient;
import com.checkout.standaloneaccountupdater.StandaloneAccountUpdaterClientImpl;
import com.checkout.tokens.TokensClient;
import com.checkout.tokens.TokensClientImpl;
import com.checkout.transfers.TransfersClient;
Expand All @@ -70,6 +78,7 @@ public class CheckoutApiImpl extends AbstractCheckoutApmApi implements CheckoutA
private final SessionsClient sessionsClient;
private final ForexClient forexClient;
private final PaymentLinksClient paymentLinksClient;
private final PaymentMethodsClient paymentMethodsClient;
private final HostedPaymentsClient hostedPaymentsClient;
private final TransfersClient transfersClient;
private final BalancesClient balancesClient;
Expand All @@ -80,12 +89,15 @@ public class CheckoutApiImpl extends AbstractCheckoutApmApi implements CheckoutA
private final PaymentContextsClient paymentContextsClient;
private final FlowClient flowClient;
private final PaymentSetupsClient paymentSetupsClient;
private final ApplePayClient applePayClient;
private final ForwardClient forwardClient;
private final FaceAuthenticationClient faceAuthenticationClient;
private final ApplicantClient applicantClient;
private final IdentityVerificationClient identityVerificationClient;
private final IdDocumentVerificationClient idDocumentVerificationClient;
private final AmlScreeningClient amlScreeningClient;
private final NetworkTokensClient networkTokensClient;
private final StandaloneAccountUpdaterClient standaloneAccountUpdaterClient;

public CheckoutApiImpl(final CheckoutConfiguration configuration) {
super(configuration);
Expand All @@ -99,6 +111,7 @@ public CheckoutApiImpl(final CheckoutConfiguration configuration) {
this.sessionsClient = new SessionsClientImpl(this.apiClient, configuration);
this.forexClient = new ForexClientImpl(this.apiClient, configuration);
this.paymentLinksClient = new PaymentLinksClientImpl(this.apiClient, configuration);
this.paymentMethodsClient = new PaymentMethodsClientImpl(this.apiClient, configuration);
this.hostedPaymentsClient = new HostedPaymentsClientImpl(this.apiClient, configuration);
this.transfersClient = new TransfersClientImpl(getTransfersClient(configuration), configuration);
this.balancesClient = new BalancesClientImpl(getBalancesClient(configuration), configuration);
Expand All @@ -112,12 +125,15 @@ public CheckoutApiImpl(final CheckoutConfiguration configuration) {
this.paymentContextsClient = new PaymentContextsClientImpl(this.apiClient, configuration);
this.flowClient = new FlowClientImpl(this.apiClient, configuration);
this.paymentSetupsClient = new PaymentSetupsClientImpl(this.apiClient, configuration);
this.applePayClient = new ApplePayClientImpl(this.apiClient, configuration);
this.forwardClient = new ForwardClientImpl(this.apiClient, configuration);
this.faceAuthenticationClient = new FaceAuthenticationClientImpl(this.apiClient, configuration);
this.applicantClient = new ApplicantClientImpl(this.apiClient, configuration);
this.identityVerificationClient = new IdentityVerificationClientImpl(this.apiClient, configuration);
this.idDocumentVerificationClient = new IdDocumentVerificationClientImpl(this.apiClient, configuration);
this.amlScreeningClient = new AmlScreeningClientImpl(this.apiClient, configuration);
this.networkTokensClient = new NetworkTokensClientImpl(this.apiClient, configuration);
this.standaloneAccountUpdaterClient = new StandaloneAccountUpdaterClientImpl(this.apiClient, configuration);
}

@Override
Expand Down Expand Up @@ -175,6 +191,11 @@ public PaymentLinksClient paymentLinksClient() {
return paymentLinksClient;
}

@Override
public PaymentMethodsClient paymentMethodsClient() {
return paymentMethodsClient;
}

@Override
public HostedPaymentsClient hostedPaymentsClient() {
return hostedPaymentsClient;
Expand Down Expand Up @@ -215,6 +236,9 @@ public MetadataClient metadataClient() {
@Override
public PaymentSetupsClient paymentSetupsClient() { return paymentSetupsClient; }

@Override
public ApplePayClient applePayClient() { return applePayClient; }

@Override
public ForwardClient forwardClient() { return forwardClient; }

Expand All @@ -233,6 +257,12 @@ public MetadataClient metadataClient() {
@Override
public AmlScreeningClient amlScreeningClient() { return amlScreeningClient; }

@Override
public NetworkTokensClient networkTokensClient() { return networkTokensClient; }

@Override
public StandaloneAccountUpdaterClient standaloneAccountUpdaterClient() { return standaloneAccountUpdaterClient; }

private ApiClient getFilesClient(final CheckoutConfiguration configuration) {
return new ApiClientImpl(configuration, new FilesApiUriStrategy(configuration));
}
Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/checkout/GsonSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.checkout.payments.sender.Sender;
import com.checkout.payments.sender.SenderType;
import com.checkout.handlepaymentsandpayouts.flow.entities.PaymentSessionStatus;
import com.checkout.handlepaymentsandpayouts.flow.responses.PaymentSubmissionResponse;
import com.checkout.webhooks.previous.WebhookResponse;
import com.checkout.workflows.actions.WorkflowActionType;
import com.checkout.workflows.conditions.WorkflowConditionType;
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/checkout/HttpMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ public String getRequestId() {
return CheckoutUtils.getRequestId(responseHeaders);
}

public String getEtag() {
return CheckoutUtils.getEtag(responseHeaders);
}

}
5 changes: 4 additions & 1 deletion src/main/java/com/checkout/OAuthScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public enum OAuthScope {
MIDDLEWARE_MERCHANTS_SECRET("middleware:merchants-secret"),
PAYMENT_CONTEXTS("gateway:payment-contexts"),
PAYMENT_SESSIONS("payment-sessions"),
PAYMENTS_SEARCH("payments:search"),
PAYOUTS_BANK_DETAILS("payouts:bank-details"),
REPORTS("reports"),
REPORTS_VIEW("reports:view"),
Expand All @@ -55,7 +56,9 @@ public enum OAuthScope {
VAULT_CARD_METADATA("vault:card-metadata"),
VAULT_INSTRUMENTS("vault:instruments"),
VAULT_TOKENIZATION("vault:tokenization"),
FORWARD("forward");
VAULT_NETWORK_TOKENS("vault:network-tokens"),
FORWARD("forward"),
FORWARD_SECRETS("forward:secrets");

private final String scope;

Expand Down
Loading
Loading