This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.
Previous versions of the Java SDK
View documentation for previous versions of the Java SDK
Java v1 SDK
This SDK was deprecated on 1 January 2024.
- Java 8 (or later) is required.
- Getting Started
- Get the source on GitHub
- Release notes
- Javadoc
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.
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.
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.Futureval 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
Product Search
Product Search is one of the most important parts of a web shop and the Java v1 SDK allows creating powerful requests.
final ProductProjectionSearch searchRequest = ProductProjectionSearch.ofCurrent().withText(Locale.ENGLISH, "shoes").withQueryFilters(m ->m.allVariants().attribute().ofEnum("size").key().is("M")).plusFacets(m -> m.categories().id().allTerms()).withSort(m -> m.name().locale(ENGLISH).asc());
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 = ReviewQueryModel //review context.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 setterfinal 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 outputfinal 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);}}