Java SDK

The Java SDK from commercetools running on the Java Virtual Machine (JVM).

About the Java SDK

The Java SDK enables developers to use Java 8 methods and objects to communicate with the commercetools platform rather than using plain HTTP calls and untyped JSON node objects. Users gain type-safety, encapsulation, IDE auto completion and an internal domain specific language to discover and formulate valid requests.

It addresses multiple languages that run on the JVM like

  • Java
  • Scala
  • Groovy
  • Clojure
  • Kotlin

In addition it uses a lot of Java 8 language constructs and classes which to provide all the great features. As a result to the Java 8 dependency the Java SDK is not usable for the Android Platform which is not (yet) supporting Java 8 on its virtual machine.

Java SDK v2

We have rewritten this SDK as replacement for the previous version of the Java SDK. Its code is autogenerated what will give you faster support for newly released API features and quicker bug fixes.

Additionally, it has exclusive support for the Machine Learning APIs and the Import API.

Java SDK v1

Deprecation notice

According to our long-term support plan we fixed the following dates along deprecation of this SDK:

  • Active Support phase ends 28 February 2022
  • Maintenance Support phase ends 31 December 2022
  • End of Life reached 1 January 2023

Features

Parallelity Features

API calls can take time and to save CPU cycles threads are not blocked.

Parallel execution

For high performance you should parallelize as much requests as possible. By using java.util.concurrent.CompletionStage from Java it is easy to start parallel asynchronous calls and combine them into a single CompletionStage.

Fetch a product and a cart in parallelJava
final CompletionStage<Product> productStage =
client.execute(ProductByIdGet.of("product-id"));
final CompletionStage<Cart> cartStage =
client.execute(CartByCustomerIdGet.of("customer-id"));
return productStage.thenCombine(cartStage, (Product product, Cart cart) -> {
final String productData = "product: " + product;
final String cartData = "cart: " + cart;
return renderTemplate(productData + " " + cartData);
});

Recover from Exceptions

API requests can fail due to network errors and other sources. With the Java SDK it is easy to code a plan B instead of crashing.

Recover from a failureJava
final CompletionStage<Product> productStage =
client.execute(ProductByIdGet.of("product-id"));
final CompletionStage<Html> htmlStage = productStage
.thenApply((Product product) -> renderTemplate("product: " + product));
final CompletionStage<Html> failSafeHtmlStage =
htmlStage.exceptionally(
(Throwable t) -> renderTemplate("Ooops, an error occured."));

Other future implementations (Scala)

To support other future implementations there are add-ons such as Scala's [Future][scala-future] (2.10, 2.11, 2.12) and Play Frameworks F.Promise (2.2, 2.3, 2.4, 2.5). We also plan to support Spring, Rx, and Reactive Streams.

import scala.concurrent.Future
val future: Future[PagedSearchResult[ProductProjection]] =
scalaSphereClient(ProductProjectionSearch.ofCurrent())

Library Features

Java Money

The SDK uses the Java Money library which makes it easy to retrieve currencies and format monetary amounts for specific locales.

final MonetaryAmount money = MoneyImpl.ofCents(123456, "USD");
assertThat(MonetaryFormats.getAmountFormat(GERMANY).format(money))
.as("German decimal separator is used")
.isEqualTo("1.234,56 USD");
assertThat(MonetaryFormats.getAmountFormat(US).format(money))
.as("in US currency comes first")
.isEqualTo("USD1,234.56");
assertThat(Monetary.getCurrency(GERMANY))
.as("find default currency for a country")
.isEqualTo(EUR);
assertThat(Monetary.getCurrency(US)).isEqualTo(USD);

Java 8 time classes

In the commercetools platform models the Java time classes are used and that can be conveniently formatted for specific time zones.

final ZonedDateTime dateTime = ZonedDateTime.parse("2015-07-09T07:46:40.230Z");
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
assertThat(dateTime.withZoneSameInstant(ZoneId.of("Europe/Berlin"))
.format(formatter))
.isEqualTo("09.07.2015 09:46");
assertThat(dateTime.withZoneSameInstant(ZoneId.of("America/New_York"))
.format(formatter))
.isEqualTo("09.07.2015 03:46");

Country codes

In the API country codes are represented as Strings, in the Java SDK models it is com.neovisionaries.i18n.CountryCode from the nv-i18n library. With the library you can format the country name according to a locale.

final CountryCode countryCode = CountryCode.US;
assertThat(countryCode.toLocale().getDisplayCountry(US))
.isEqualTo("United States");
assertThat(countryCode.toLocale().getDisplayCountry(GERMANY))
.isEqualTo("Vereinigte Staaten von Amerika");
assertThat(countryCode.toLocale().getDisplayCountry(FRANCE))
.isEqualTo("Etats-Unis");
assertThat(countryCode.getAlpha2())
.isEqualTo("US");

Logging Features

For logging SLF4J is used.

For each commercetools platform resource you can specify a custom log level. Moreover, it is possible to set the level for request or response objects and fine-tune them for read and write access to the API.

The trace level logs the JSON objects in a pretty printed way - this way you can directly analyze what was sent to or received from the commercetools platform HTTP API.

Domain Specific Languages for creating requests

Query

Creating queries for deep nested objects works like a charm.

OrderQuery.of()
.withPredicates(m -> m.customerGroup()
.id().is("customer-group-id"))
.plusPredicates(m -> m.shipmentState()
.isNot(ShipmentState.SHIPPED))
.withSort(m -> m.createdAt().sort().asc());

Reference Expansion

Fetching multiple objects in request can be done by reference expansion.

final ReviewByIdGet reviewRequest = ReviewByIdGet.of("review-id")
.plusExpansionPaths(m -> m.customer());
final Review review = client.executeBlocking(reviewRequest);
final Customer customer = review.getCustomer().getObj();

Type-safety

In a useful way objects are typed and so the compiler checks for some copy paste errors.

final QueryPredicate<Review> predicate = //review context
ReviewQueryModel.of().id().is("review-id");
ReviewQuery.of()
.plusPredicates(predicate);//compiles
//OrderQuery.of()//wrong context
//.plusPredicates(predicate);//doesn't compile

Flexibility above the Java SDK core

Even if a predicate, an expansion path or a sort expression is not yet supported in the SDK, String expressions can be used as fallback.

final QueryPredicate<Product> safePredicate = ProductQueryModel.of()
.masterData().current().name()
.lang(ENGLISH).isIn(asList("foo", "bar"));
final String s =
"masterData(current(name(en in (\"foo\", \"bar\"))))";
final QueryPredicate<Product> unsafePredicate =
QueryPredicate.of(s);
assertThat(unsafePredicate).isEqualTo(safePredicate);

Immutability

Immutable objects can be freely shared in a multi-threaded environment. The Java SDK resource types are immutable by default. Also typical requests are immutable and provide an API to create adjusted copies which fit well in a functional programming style.

final ProductProjection product = getProduct();
//product.setName("new name");//no bean setter
final CategoryQuery query = CategoryQuery.of();
final CategoryQuery query2 = query.withLimit(30);
assertThat(query == query2).isFalse();

Modularity Features

It is possible to just use the SDK to get an access token

The Java SDK enables you to fetch an access token for a commercetools platform project.

final SphereAuthConfig authConfig = SphereAuthConfig
.of("project-key", "clientId", "clientSecret");
final CompletionStage<String> accesstokenStage =
TokensFacade.fetchAccessToken(authConfig);

Java models not required but provided

If the Java models don't fit you use cases you can create your own model classes or just use directly JSON in Java.

final ProductProjectionSearch searchWithJavaModel =
ProductProjectionSearch.ofStaged()
.withPriceSelection(PriceSelection.of(EUR))
.withExpansionPaths(m -> m.categories())
.withSort(m -> m.createdAt().desc())
.withLimit(10);
final PagedSearchResult<ProductProjection> result =
client.executeBlocking(searchWithJavaModel);
final JsonNodeSphereRequest jsonNodeSphereRequest =
JsonNodeSphereRequest.of(searchWithJavaModel);
assertThat(searchWithJavaModel.httpRequestIntent())
.isEqualTo(jsonNodeSphereRequest.httpRequestIntent());
//different output
final JsonNode jsonNode =
client.executeBlocking(jsonNodeSphereRequest);

Testable request and response handling

If the Java models don't fit you use cases you can create your own model classes or just use directly JSON in Java.

final SphereClient asyncClient = TestDoubleSphereClientFactory
.createHttpTestDouble(httpRequest ->
HttpResponse.of(200, "{\n" +
" \"id\" : \"category-id\",\n" +
" \"version\" : 1,\n" +
" \"name\" : {\n" +
" \"en\" : \"engl. name\"\n" +
" },\n" +
" \"slug\" : {\n" +
" \"en\" : \"slug\"\n" +
" }\n" +
"}"));
final BlockingSphereClient client = BlockingSphereClient
.of(asyncClient, 3, TimeUnit.SECONDS);
final Category category =
client.executeBlocking(CategoryByIdGet.of("category-id"));
assertThat(category.getName().get(ENGLISH)).isEqualTo("engl. name");

Java SDK supports multiple HTTP client implementation for compatibility and speed

Async HTTP client is a very fast and verbose HTTP client but has problems in some projects concerning compatibility of this library and to the netty library. This can be solved by picking a specific version or fall back to the Apache HTTP client. Also it is possible to configure the underlying client for example to deal with proxies.

final String[] enabledProtocols = {"TLSv1.2"};
final DefaultAsyncHttpClientConfig config =
new DefaultAsyncHttpClientConfig.Builder()
.setEnabledProtocols(enabledProtocols)
.build();
final Supplier<HttpClient> httpClientSupplier =
() -> AsyncHttpClientAdapter.of(new DefaultAsyncHttpClient(config));
final SphereClientFactory factory =
SphereClientFactory.of(httpClientSupplier);
final SphereClient client =
factory.createClient("project-key", "clientId", "clientSec");

Dependencies

Hard dependencies are

  • Java 8 (platform)
  • commons-lang3 (StringUtils, HashCodeBuilder, EqualsBuilder, ToStringBuilder)
  • slf4j-api (logging)
  • com.google.code.findbugs:jsr305 (nullable annotation)
  • org.javamoney:moneta (money library)
  • com.neovisionaries:nv-i18n (country code library)
  • a lot of Jackson JSON mapper libraries (com.fasterxml.jackson, JSON processing)

The HTTP underlying client can be selected from

  • com.ning:async-http-client:1.8.x
  • com.ning:async-http-client:1.9.x
  • org.asynchttpclient:async-http-client:2.0.x
  • org.apache.httpcomponents:httpcore:4.4.4

The Java SDK core does not depend on Play Framework, Scala, Spring, or Groovy.

Examples and Templates

Please check out the following examples and templates. They are a very good way to start using the platform.

All examples and templates are open source software. The code is publicly available on GitHub. Artifacts are also published on Maven Central.

commercetools Hello Maven Archetype

Simple Maven archetype to create a Java application with a main method which does a request to the commercetools platform. It prints the product names and the category names it is in.

For more information visit its GitHub repo.

commercetools Hello Example with Gradle

The repository commercetools-hello-api-java shows how to use the Java SDK with a Gradle 2 project. It prints out the product names and the names of the categories the product is assigned to.

commercetools Hello Scala Activator Template

The template provides a minimal Scala application which uses Scala Futures instead of the Java CompletionStages and shows the usage of Scala closures to express product queries.

Reproducer App

The reproducer app is a playground to get to know exceptions in the Java SDK as well as fine tune the log level.

Spring Model View Controller (MVC) Archetype

This archetype is a simple example integrating the commercetools Java SDK with Spring MVC and Spring DI. It just shows some products using an async API.

Sunrise Play Java Shop

Sunrise Java is a template shop, that can be used by developers to see a standard storefront on the project data and to learn from the implementation.

Donut

Donut Store is a free template for subscription e-commerce sites and it's built on top of the APIs of Pactas, Paymill, and the commercetools platform.

Integrations

Play Framework Integration

Play Frameworks uses a proprietary "future" (F.Promise = async result object) implementation for the versions 2.2, 2.3, 2.4 and 2.5. commercetools provides a wrapper for the commercetools client to produce F.Promise instead of CompletionStage. In Play Framework 2.5 F.Promises are deprecated and CompletionStage is used instead so this module is not required anymore.

Scala Integration

The Scala add-ons for the Java SDK provides as future implementation scala.concurrent.Future instead of CompletionStage. Also it enables to use the domain specific language of the Java SDK to formulate requests. With the current Scala version Java 8 lambdas cannot directly expressed in Scala.

Reactive Streams Integration

The reactive streams add-ons provide facilities to fetch all resources of a certain criteria with transparently handling pagination.

Example to create a reactive streams publisher:

import io.sphere.sdk.client.SphereClient;
import io.sphere.sdk.products.Product;
import io.sphere.sdk.products.queries.ProductQuery;
import io.sphere.sdk.reactivestreams.SphereReactiveStreams;
import org.reactivestreams.Publisher;
public class QueryAllIdentifiableDemo {
public static void demo(final SphereClient client) {
final Publisher<Product> productPublisher =
SphereReactiveStreams.publisherOf(ProductQuery.of(), client);
}
}