This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.
Customizing the Java SDK
Serialization
The SDK uses Jackson for serializing and deserializing JSON. The default configured ObjectMapper
uses some modules to correctly work with commercetools APIs. The details can be found in JsonUtils.createObjectMapper(ModuleOptions).
Customization
To allow customization of the ObjectMapper
, the SDK uses ServiceLoader for ModuleSupplier. Adding the file resources/META-INF/services/io.vrap.rmf.base.client.utils.json.ModuleSupplier
to your project with the fully qualified class name of the module supplier to be used will register the supplied modules.
io.vrap.rmf.base.client.utils.json.ModuleSupplier:com.commercetools.api.json.ApiModuleSupplier
package com.commercetools.api.json;import java.util.Optional;import com.commercetools.api.models.cart.ReplicaCartDraft;import com.commercetools.api.models.product.AttributeImpl;import com.commercetools.api.models.review.Review;import com.commercetools.api.models.type.FieldContainerImpl;import com.fasterxml.jackson.databind.module.SimpleModule;import io.vrap.rmf.base.client.utils.json.modules.ModuleOptions;/*** Module to configure the default jackson {@link com.fasterxml.jackson.databind.ObjectMapper} e.g. to deserialize attributes and custom fields*/public class ApiModule extends SimpleModule {private static final long serialVersionUID = 0L;public ApiModule(ModuleOptions options) {boolean attributeAsDateString = Boolean.parseBoolean(Optional.ofNullable(options.getOption(ApiModuleOptions.DESERIALIZE_DATE_ATTRIBUTE_AS_STRING)).orElse(System.getProperty(ApiModuleOptions.DESERIALIZE_DATE_ATTRIBUTE_AS_STRING)));boolean customFieldAsDateString = Boolean.parseBoolean(Optional.ofNullable(options.getOption(ApiModuleOptions.DESERIALIZE_DATE_FIELD_AS_STRING)).orElse(System.getProperty(ApiModuleOptions.DESERIALIZE_DATE_FIELD_AS_STRING)));addDeserializer(AttributeImpl.class, new AtrributeDeserializer(attributeAsDateString));addDeserializer(FieldContainerImpl.class, new CustomFieldDeserializer(customFieldAsDateString));setMixInAnnotation(Review.class, ReviewMixin.class);setMixInAnnotation(ReplicaCartDraft.class, ReplicaCartDraftMixin.class);}}
DateTime attributes
When using Date, Time and DateTime types for Product attributes or Custom Fields the SDK deserializes them as LocalDate, LocalTime and ZonedDateTime.
To deserialize them as a String, the ObjectMapper can be configured with ModuleOptions. The ApiModule also loads the configuration options using System.getProperty(String)
(for example: commercetools.deserializeDateAttributeAsString).
ApiModuleOptions options = ApiModuleOptions.of().withDateAttributeAsString(true).withDateCustomFieldAsString(true);ObjectMapper mapper = JsonUtils.createObjectMapper(options);ProjectApiRoot apiRoot = ApiRootBuilder.of().withApiBaseUrl(ServiceRegion.GCP_EUROPE_WEST1.getApiUrl()).withSerializer(ResponseSerializer.of(mapper)).build("test");ProductVariant variant = mapper.readValue(stringFromResource("attributes.json"),ProductVariant.class);assertThat(variant.getAttributes()).isNotEmpty();Map<String, Attribute> attributes = variant.withProductVariant(AttributeAccessor::asMap);assertThat(attributes.get("date").getValue()).isInstanceOfSatisfying(String.class,localDate -> assertThat(localDate).isEqualTo("2020-01-01"));assertThat(attributes.get("time").getValue()).isInstanceOfSatisfying(String.class,localTime -> assertThat(localTime).isEqualTo("13:15:00.123"));assertThat(attributes.get("datetime").getValue()).isInstanceOfSatisfying(String.class,dateTime -> assertThat(dateTime).isEqualTo("2020-01-01T13:15:00.123Z"));assertThat(attributes.get("date").withAttribute(AttributeAccessor::asDate)).isInstanceOfSatisfying(LocalDate.class,localDate -> assertThat(localDate).isEqualTo("2020-01-01"));assertThat(attributes.get("time").withAttribute(AttributeAccessor::asTime)).isInstanceOfSatisfying(LocalTime.class,localTime -> assertThat(localTime).isEqualTo("13:15:00.123"));assertThat(attributes.get("datetime").withAttribute(AttributeAccessor::asDateTime)).isInstanceOfSatisfying(ZonedDateTime.class,dateTime -> assertThat(dateTime).isEqualTo("2020-01-01T13:15:00.123Z"));assertThat(attributes.get("set-date").getValue()).asList().first().isInstanceOf(String.class);assertThat(attributes.get("set-time").getValue()).asList().first().isInstanceOf(String.class);assertThat(attributes.get("set-datetime").getValue()).asList().first().isInstanceOf(String.class);assertThat(attributes.get("set-date").withAttribute(AttributeAccessor::asSetDate)).asList().first().isInstanceOf(LocalDate.class);assertThat(attributes.get("set-time").withAttribute(AttributeAccessor::asSetTime)).asList().first().isInstanceOf(LocalTime.class);assertThat(attributes.get("set-datetime").withAttribute(AttributeAccessor::asSetDateTime)).asList().first().isInstanceOf(ZonedDateTime.class);
Tuning the client
Blocking execution
In some frameworks there is no support for asynchronous execution and so it is necessary to wait for the responses.
The client can wait for responses with the method .executeBlocking()
.
This method enforces a timeout for resilience and throws an ApiHttpException
.
ProjectApiRoot apiRoot = createProjectClient();Project project = apiRoot.get().executeBlocking().getBody();
Configure the underlying HTTP client
The ApiRootBuilder
has create methods which allow passing a preconfigured HTTP client.
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy", 8080));VrapHttpClient httpClient = new CtOkHttp4Client(builder -> builder.proxy(proxy));ProjectApiRoot apiRoot = ApiRootBuilder.of(httpClient).defaultClient(ClientCredentials.of().withClientId("your-client-id").withClientSecret("your-client-secret").withScopes("your-scopes").build(),ServiceRegion.GCP_EUROPE_WEST1).build("my-project");