Migrate from v1 to v2

How to migrate from the v1 SDK to the v2 SDK .

The Java v1 SDK will be deprecated on 1 January 2024. This guide helps developers migrate from the v1 SDK to the Java v2 SDK.

Placeholder values

Example code in this migration guide uses placeholders that should be replaced with the following values:

PlaceholderReplace withFrom
{projectKey}project_keyyour API Client
{clientID}client_idyour API Client
{clientSecret}secretyour API Client
{scope}scopeyour API Client
{region}your RegionHosts

Client configuration and creation

SphereClientFactory has been replaced by ApiRootBuilder.

The benefit is that after the ApiRoot has been instantiated, requests can be created directly from it.

Example code from Java SDK v1Java
final SphereClient sphereClient = SphereClientFactory
.of()
.createClient("{projectKey}", "{clientID}", "{clientSecret}");
Example code for Java SDK v2Java
final ProjectApiRoot projectRoot = ApiRootBuilder
.of()
.defaultClient(
ClientCredentials
.of()
.withClientId("{clientID}")
.withClientSecret("{clientSecret}")
.build(),
ServiceRegion.GCP_EUROPE_WEST1
)
.build("{projectKey}");

Timeout setting

Both SDKs use the method executeBlocking() to set the timeout.

Example code from Java SDK v1Java
PagedQueryResult<Category> response = blockingClient()
.executeBlocking(CategoryQuery.of(), 45, TimeUnit.SECONDS);
Example code for Java SDK v2Java
CategoryPagedQueryResponse response = projectClient()
.categories()
.get()
.executeBlocking(Duration.ofSeconds(45))
.getBody();

Headers

To set headers, in the v1 SDK there is the HttpRequest class and in the v2 SDK the ApiHttpRequest class.

The main difference, as you can see in the example below, is that the ApiHttpRequest can be directly instantiated and it can set the type of method (GET or POST), the URI, the headers, and the body.

Example code from Java SDK v1Java
// Not in SDK v1
Example code for Java SDK v2Java
final CartPagedQueryResponse carts = projectClient()
.carts()
.get()
.addHeader("foo", "bar")
.executeBlocking()
.getBody();

Implementing retry

In the examples below there is a significant difference in the retry mechanisms between the v1 SDK and the v2 SDK.

In the v1 SDK, the retry mechanism has to be defined piece by piece: first the retry rules, then the SphereClient, and then the request, in this case, a PagedQueryResult

In the v2 SDK, the setup of the request can be built directly during the client creation. ByProjectKeyRequestBuilder can be created with a built-in retry mechanism using the RetryMiddleware. It is also possible to set up additional parameters to the request, like the logger InternalLoggerFactory.

Example code from Java SDK v1Java
final int maxAttempts = 5;
final List<RetryRule> retryRules = singletonList(
RetryRule.of(
RetryPredicate.ofMatchingStatusCodes(
BAD_GATEWAY_502,
SERVICE_UNAVAILABLE_503,
GATEWAY_TIMEOUT_504
),
RetryAction.ofExponentialBackoff(maxAttempts, 100, 2000)
)
);
final SphereClient client = RetrySphereClientDecorator.of(
sphereClient(),
retryRules
);
final PagedQueryResult<Category> categoryPagedQueryResult = client
.execute(CategoryQuery.of())
.toCompletableFuture()
.get();
Example code for Java SDK v2Java
final ByProjectKeyRequestBuilder projectClient = ApiRootBuilder
.of()
.defaultClient(
ServiceRegion.GCP_EUROPE_WEST1.getApiUrl(),
ClientCredentials
.of()
.withClientId("{clientId}")
.withClientSecret("{clientSecret}")
.build(),
ServiceRegion.GCP_EUROPE_WEST1.getOAuthTokenUrl()
)
.withRetryMiddleware(5, Arrays.asList(502, 503, 504))
.buildForProject("{projectKey}");
final CategoryPagedQueryResponse body = projectClient
.categories()
.get()
.executeBlocking()
.getBody();

Using DraftBuilders

In the v2 SDK there are not inheritances for DraftBuilder classes, but the differences are minor.

Example code from Java SDK v1Java
LocalizedString name = LocalizedString.ofEnglish("name");
LocalizedString slug = LocalizedString.ofEnglish("slug");
LocalizedString metaDescription = LocalizedString.ofEnglish("metaDescription");
LocalizedString metaTitle = LocalizedString.ofEnglish("metaTitle");
LocalizedString metaKeywords = LocalizedString.ofEnglish("metaKeywords");
CategoryDraft categoryDraft = CategoryDraftBuilder
.of(name, slug)
.metaDescription(metaDescription)
.metaTitle(metaTitle)
.metaKeywords(metaKeywords)
.externalId("externalId")
.build();
Example code for Java SDK v2Java
CategoryDraft categoryDraft = CategoryDraft
.builder()
.name(LocalizedString.ofEnglish("name"))
.slug(LocalizedString.ofEnglish("slug"))
.externalId("externalId")
.metaTitle(LocalizedString.ofEnglish("metaTitle"))
.metaDescription(LocalizedString.ofEnglish("metaDescription"))
.metaKeywords(LocalizedString.ofEnglish("metaKeywords"))
.build();

Create resources

In the v2 SDK there are no dedicated classes for the create command, but there are builders instead. The Create Command needs a Draft that is built and passed to the post() method.

Example code from Java SDK v1Java
LocalizedString name = LocalizedString.ofEnglish("name");
LocalizedString slug = LocalizedString.ofEnglish("slug");
CategoryDraft categoryDraft = CategoryDraftBuilder.of(name, slug).build();
Category category = blockingClient()
.executeBlocking(CategoryCreateCommand.of(categoryDraft));
Example code for Java SDK v2Java
CategoryDraft categoryDraft = CategoryDraft
.builder()
.name(LocalizedString.ofEnglish("name"))
.slug(LocalizedString.ofEnglish("slug"))
.build();
Category category = projectClient()
.categories()
.post(categoryDraft)
.executeBlocking()
.getBody();

Create resources from JSON

In the v2 SDK, the JsonUtils class replaces the SphereJsonUtils class.

Example code from Java SDK v1Java
final CategoryDraft categoryDraft = SphereJsonUtils.readObjectFromResource(
"category.json",
CategoryDraft.class
);
final Category category = blockingClient()
.executeBlocking(CategoryCreateCommand.of(categoryDraft));
Example code for Java SDK v2Java
final CategoryDraft categoryDraft = JsonUtils.fromJsonString(
TestUtils.stringFromResource("category.json"),
CategoryDraft.class
);
final Category category = projectClient()
.categories()
.post(categoryDraft)
.executeBlocking()
.getBody();

Update resources

In the v2 SDK there are no dedicated classes for the update command. The UpdateBuilder is used to create the type of update action to apply in the post() method.

Example code from Java SDK v1Java
LocalizedString newName = LocalizedString.ofEnglish("new name");
CategoryUpdateCommand command = CategoryUpdateCommand.of(
category,
Collections.singletonList(ChangeName.of(newName))
);
Category updatedCategory = blockingClient().executeBlocking(command);
Example code for Java SDK v2Java
CategoryUpdate categoryUpdate = CategoryUpdate
.builder()
.version(category.getVersion())
.plusActions(actionBuilder ->
actionBuilder
.changeNameBuilder()
.name(LocalizedString.ofEnglish("new name"))
)
.build();
Category updatedCategory = projectClient()
.categories()
.withId(category.getId())
.post(categoryUpdate)
.executeBlocking()
.getBody();

Get a resource by ID

Retrieving resources by ID in the v2 SDK requires .withId() before .get(), after which additional filters or requests (such as .withExpand()) can be included before the request is executed.

Example code from Java SDK v1Java
Category loadedCategory = blockingClient()
.executeBlocking(
CategoryByIdGet.of(category.getId()).withExpansionPaths(m -> m.parent())
);
Example code for Java SDK v2Java
Category queriedCategory = projectClient()
.categories()
.withId(category.getId())
.get()
.withExpand("parent")
.executeBlocking()
.getBody();

Query resources

To build complex queries, the v2 SDK uses ResourcePagedQueryResponse (as opposed to PagedQueryResult in the v1 SDK). ResourcePagedQueryResponse can apply the limit, count, total, offset, and result to the query.

Example code from Java SDK v1Java
PagedQueryResult<Category> pagedQueryResult = blockingClient()
.executeBlocking(CategoryQuery.of().byId("id123"));
Example code for Java SDK v2Java
CategoryPagedQueryResponse response = projectClient()
.categories()
.get()
.withWhere("id = :id", "id", "id123")
.executeBlocking()
.getBody();

Compatibility layer for JVM SDK

The commercetools-sdk-compat-v1 module allows the usage of the v2 SDK in conjunction with the v1 SDK.

Using Requests from the JVM SDK

The CompatClient can be used to execute a SphereRequest with an ApiHttpClient.

import com.commercetools.api.defaultconfig.ApiRootBuilder;
import com.commercetools.api.models.project.Project;
import io.sphere.sdk.projects.queries.ProjectGet;
import io.vrap.rmf.base.client.ApiHttpClient;
import io.vrap.rmf.base.client.oauth2.ClientCredentials;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
public class CompatClientUsageTest {
@Test
public void compatClient() {
final ApiHttpClient apiHttpClient = ApiRootBuilder.of()
.defaultClient(ClientCredentials.of()
.withClientId(CommercetoolsTestUtils.getClientId())
.withClientSecret(CommercetoolsTestUtils.getClientSecret())
.build())
.buildClient();
final String projectKey = CommercetoolsTestUtils.getProjectKey();
CompatClient client = CompatClient.of(apiHttpClient, projectKey);
Project project = client.executeBlocking(ProjectGet.of(), Project.class).getBody();
Assertions.assertThat(project).isInstanceOf(Project.class);
Assertions.assertThat(project.getKey()).isEqualTo(projectKey);
}
}

Creating a SphereClient with the V2 SDK

The CompatSphereClient acts as a replacement SphereClient for applications using the v1 SDK.

public class CompatSphereClientUsageTest {
@Test
public void sphereCompatClient() throws ExecutionException, InterruptedException {
SphereClientConfig clientConfig = SphereClientConfig.of(CommercetoolsTestUtils.getProjectKey(),
CommercetoolsTestUtils.getClientId(), CommercetoolsTestUtils.getClientSecret());
SphereClient client = CompatSphereClient.of(clientConfig);
Project project = client.execute(ProjectGet.of()).toCompletableFuture().get();
Assertions.assertThat(project).isInstanceOf(Project.class);
}
}