Integrate applications running on the Java Virtual Machine (JVM) with Composable Commerce.
The Java SDK (also referred to as the Java v2 SDK) enables you to use Java 8 methods and objects to interact with Composable Commerce APIs rather than using plain HTTP calls and untyped JSON node objects. With the Java SDK, you can make use of IDE autocompletion, type-safety, encapsulation, and an internal domain-specific language for formulating valid requests.
The Java SDK supports multiple languages that run on the JVM, including Java, Scala, Groovy, Clojure, and Kotlin.
Get started
Migration from v1
SDK features
The Java SDK uses various Java 8 language constructs and classes, including:
- CompletionStage
- Functional interfaces
- Java Date API:
As a result of Java 8 dependencies, the Java SDK is unsuitable for Android development as it does not support Java 8 on its virtual machine.
The SDK simplifies development with:
- Default implementations for equals() and hashCode(): automatically using reflection in model implementation classes.
- Client interfaces: the HTTP client abstract is a functional interface, and you can replace it with test doubles.
- Model factory methods: each model has a factory method
::of()
to create a new empty instance. The method::builder()
returns a new builder instance. - Helper methods: you can find a complete list of helper methods including example usage in the Javadoc.
Best practices and error handling
Exceptions
- Problems related to the ApiHttpClient result in an ApiHttpException.
- JSON serializing and deserializing problems result in a JsonException.
- ApiHttpException is a base exception for all error responses (HTTP status codes
4xx
and5xx
). - ApiClientException indicates the client-side errors that can be recovered (HTTP status codes
4xx
). - ApiServerException represents server errors.
Errors
Custom HttpExceptionFactory
4xx
and 5xx
as errors and raises exceptions. The DefaultHttpExceptionFactory creates these exceptions. To customize the handling, you must implement this interface and override its default methods as needed.public class HttpExceptionFactoryTest {
static class CustomExceptionFactory implements HttpExceptionFactory {
@Override
public ApiHttpException create(
ApiHttpRequest request,
ApiHttpResponse<byte[]> response
) {
return new ApiHttpException(
response.getStatusCode(),
request.getSecuredBody(),
response.getHeaders(),
"something bad happened",
response,
request
);
}
@Override
public ResponseSerializer getResponseSerializer() {
return ResponseSerializer.of();
}
}
@Test
public void customFactory() {
ProjectApiRoot client = ApiRootBuilder
.of()
.defaultClient(ServiceRegion.GCP_EUROPE_WEST1.getApiUrl())
.withHttpExceptionFactory(CustomExceptionFactory::new)
.build("my-project-key");
assertThatExceptionOfType(ApiHttpException.class)
.isThrownBy(() -> client.get().executeBlocking())
.withMessageStartingWith("detailMessage: something bad happened");
}
}
Logging
commercetools
.The default logger middleware logs the following information per level:
- Error: logs HTTP method, URI, and response status code for ApiHttpException, and cause and exceptions for all other exceptions.
- Information: logs HTTP method, URI, response status code, and any deprecation notices. You can configure the log level when instantiating the InternalLoggerMiddleware.
- Debug: logs string representations of the request and the response, including headers and body, with sensitive data like auth tokens and passwords, redacted.
- Trace: Logs request and response with pretty-printed output, with sensitive information redacted.
Logger hierarchy
commercetools
. The child loggers of commercetools are the endpoints. For example commercetools.categories
for Categories and commercetools.product-types
for Product Types.commercetools.categories.request
refers to performing requests per HTTPS to commercetools for Categories, commercetools.categories.response
refers to the responses.commercetools.categories.response
logs the HTTP response on debug level: [OkHttp https://api.europe-west1.gcp.commercetools.com/...] DEBUG commercetools.categories.response - io.vrap.rmf.base.client.ApiHttpResponse@33e37acd[statusCode=200,headers=...,textInterpretedBody={"limit":20,"offset":0,"count":4,"total":4,"results":[{"id":"ca7f64dc-ab41-4e7f-b65b-bfc25bf01111","version":1,"createdAt":"2021-01-06T09:21:55.445Z","lastModifiedAt":"2021-01-06T09:21:55.445Z","key":"random-key-15aab6ee-9a48-4fdc-a8c3-8ff9ff390d60","name":{"key-6bc3cc62-1995-43f4":"value-random-string-c3ff7f1a-6371-4c0c-a3b9-5060eca08b8a"},"slug":{"key-6bc3cc62-1995-43f4":"value-random-string-c3ff7f1a-6371-4c0c-a3b9-5060eca08b8a"},"description":{"key-6bc3cc62-1995-43f4":"value-random-string-c3ff7f1a-6371-4c0c-a3b9-5060eca08b8a"},"ancestors":[],"orderHint":"random-string-a99e6941-3225-4766-923a-4a654652532f","externalId":"random-id-100b3851-29b4-47c1-aef3-860b4cd28f54"}]}]
commercetools.categories.response
logs the formatted HTTP response on trace level:[OkHttp https://api.europe-west1.gcp.commercetools.com/...] TRACE commercetools.categories.response - 200
{
"limit" : 20,
"offset" : 0,
"count" : 4,
"total" : 4,
"results" : [ {
"id" : "bcb15128-b69e-47b6-81c4-1ea5f9a63b83",
"version" : 1,
"createdAt" : "2021-01-06T09:21:50.485Z",
"lastModifiedAt" : "2021-01-06T09:21:50.485Z",
"createdBy" : {
"clientId" : "h-QvaF3NpsjPBWeXa6TUOnq0",
"isPlatformClient" : false
},
"key" : "random-key-f45535f5-1111-4bfb-98ac-164234ac2c73",
"name" : {
"key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a"
},
"slug" : {
"key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a"
},
"description" : {
"key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a"
},
"ancestors" : [ ],
"orderHint" : "random-string-6b88f299-d4ca-491a-9d7c-3463e718c8d2",
"externalId" : "random-id-b98a5ab4-5413-40b3-8119-eb5ac2b5afbb",
"metaTitle" : {
"key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a"
},
"metaKeywords" : {
"key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a"
},
"metaDescription" : {
"key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a"
}
}, {
...
} ]
}
commercetools.products.responses.queries
only logs HTTP GET requests and commercetools.products.responses.commands
only logs HTTP POST/DELETE requests.[pool-1-thread-1] DEBUG commercetools.products.request.commands - io.vrap.rmf.base.client.ApiHttpRequest@1d2c6948[method=POST,uri="https://api.europe-west1.gcp.commercetools.com/test-php-dev-integration-1/products",headers=[...],textInterpretedBody={"productType":{"id":"cda39953-23af-4e85-abb0-5b89517ec5f2","typeId":"product-type"},"name":{"random-string-b66de021-d2fa-4262-8837-94a6992a8cdc":"random-string-da28a010-e66b-49d4-a18b-f1bfc145d2f6"},...}]
[pool-1-thread-1] DEBUG commercetools.products.request.queries - io.vrap.rmf.base.client.ApiHttpRequest@53667fdb[method=GET,uri="https://api.europe-west1.gcp.commercetools.com/test-php-dev-integration-1/products/ef745227-b115-4132-ba2c-4e46db80df79",headers=[...],textInterpretedBody=empty body]