Previous versions of the Java SDK

View documentation for previous versions of the Java SDK

Java v1 SDK

Deprecation notice

According to our long-term support plan, the following dates apply to the Java v1 SDK:

  • Active Support phase ended 28 February 2022
  • Maintenance Support phase ends 31 December 2023
  • Reaches End of Life on 1 January 2024

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 requests whenever 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. The Java v1 SDK provides ways to recover from Exceptions.

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 (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 Java v1 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

Java time classes are used and 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 v1 SDK they are com.neovisionaries.i18n.CountryCode from the nv-i18n library. With this 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 Composable Commerce resource you can specify a custom log level. It is also 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 HTTP API.

Domain Specific Languages for creating requests

Query

Query deep nested objects.

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 performed using 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

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 v1 SDK core

Even if a predicate, an expansion path, or a sort expression is not yet supported in the Java v1 SDK, String expressions can be used as a 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 v1 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

Use the Java v1 SDK to get an access token

The Java v1 SDK enables you to fetch an access token for a commercetools 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");

Multiple HTTP client implementations for compatibility and speed

Async HTTP client is a fast and verbose HTTP client but can have problems in cases concerning compatibility to the netty library. This can be solved by picking a specific version or implementing a fallback to the Apache HTTP client. Also, it is possible to configure the underlying client 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
  • 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 underlying HTTP 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 v1 SDK core does not depend on the Play Framework, Scala, Spring, or Groovy.

Examples and Templates

The below examples and templates provide additional support in integrating with the Java v1 SDK.

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 that performs requests to the Composable Commerce API. It prints Product names and the Categories that Products belong to.

For more information visit its GitHub repo.

commercetools Hello Example with Gradle

The repository commercetools-hello-api-java shows how to use the Java v1 SDK with a Gradle 2 project. It prints Product names and the Categories that Products belong to.

commercetools Hello Scala Activator Template

The template provides a minimal Scala application that 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 v1 SDK as well as the fine-tuning of log levels.

Spring Model View Controller (MVC) Archetype

This archetype is an example that integrates the Java v1 SDK with Spring MVC and Spring DI. It shows how to fetch Products using an async API.

Sunrise Play Java Shop

Sunrise Java is a template shop, that can be used by developers to explore an example storefront.

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 commercetools.

Integrations

Play Framework Integration

The Play Frameworks uses a proprietary Future implementation (F.Promise = async result object) 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 v1 SDK][scala-add-ons] provide a Future implementation scala.concurrent.Future instead of CompletionStage. It supports the domain-specific language of the Java v1 SDK to formulate requests. With the current Scala version, Java 8 lambdas cannot be directly expressed in Scala.

Reactive Streams Integration

The reactive streams add-ons provide facilities to fetch all resources of certain criteria whilst 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);
}
}