Migrate from v1 to v2
How to migrate from the v1 SDK to the v2 SDK.
The Java v1 SDK was deprecated on 1 January 2024.
Differences between v1 and v2 SDKs
See the following links for more information on differences between the v1 and v2 SDKs.
Migration guides
You can follow one of these approaches to migrate from Java v1 to v2.
Placeholder values
Example code in this guide uses the following placeholder values. You should replace these placeholders with the following values:
Placeholder | Replace with | From |
---|---|---|
{projectKey} | project_key | your API Client |
{clientID} | client_id | your API Client |
{clientSecret} | secret | your API Client |
{scope} | scope | your API Client |
{region} | your Region | Hosts |
Manually migrate to v2 SDK
The following example code demonstrates how to perform an action using the Java v1 SDK, and the best practice for replicating this action with the Java v2 SDK.
Client configuration and creation
SphereClientFactory
has been replaced by ApiRootBuilder
.
The benefit is that after the ApiRoot
has been instantiated, you can create requests directly from it.
final SphereClient sphereClient = SphereClientFactory.of().createClient("{projectKey}", "{clientID}", "{clientSecret}");
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.
PagedQueryResult<Category> response = blockingClient().executeBlocking(CategoryQuery.of(), 45, TimeUnit.SECONDS);
CategoryPagedQueryResponse response = projectClient().categories().get().executeBlocking(Duration.ofSeconds(45)).getBody();
Exception handling
In the v1 SDK, the SphereClient
throws the underlying exception when it occurs. In the v2 SDK, the ProjectRoot
throws an CompletionException
instead and the actual exception is wrapped inside it.
The ClientBuilder.withErrorMiddleware(ErrorMiddleware.ExceptionMode)
method allows you to configure the middleware to unwrap the causing exception.
final ProjectApiRoot projectRoot = ApiRootBuilder.of().defaultClient(ClientCredentials.of().withClientId("{clientID}").withClientSecret("{clientSecret}").build(),ServiceRegion.GCP_EUROPE_WEST1).withErrorMiddleware(ErrorMiddleware.ExceptionMode.UNWRAP_COMPLETION_EXCEPTION).build("{projectKey}");
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.
// Not in SDK v1
final CartPagedQueryResponse carts = projectClient().carts().get().addHeader("foo", "bar").executeBlocking().getBody();
Implementing retry
The retry mechanisms are significantly different 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
.
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();
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.
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();
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.
LocalizedString name = LocalizedString.ofEnglish("name");LocalizedString slug = LocalizedString.ofEnglish("slug");CategoryDraft categoryDraft = CategoryDraftBuilder.of(name, slug).build();Category category = blockingClient().executeBlocking(CategoryCreateCommand.of(categoryDraft));
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.
final CategoryDraft categoryDraft = SphereJsonUtils.readObjectFromResource("category.json",CategoryDraft.class);final Category category = blockingClient().executeBlocking(CategoryCreateCommand.of(categoryDraft));
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.
LocalizedString newName = LocalizedString.ofEnglish("new name");CategoryUpdateCommand command = CategoryUpdateCommand.of(category,Collections.singletonList(ChangeName.of(newName)));Category updatedCategory = blockingClient().executeBlocking(command);
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();
For more examples of update actions in the v2 SDK, see the integration tests.
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.
Category loadedCategory = blockingClient().executeBlocking(CategoryByIdGet.of(category.getId()).withExpansionPaths(m -> m.parent()));
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.
PagedQueryResult<Category> pagedQueryResult = blockingClient().executeBlocking(CategoryQuery.of().byId("id123"));
CategoryPagedQueryResponse response = projectClient().categories().get().withWhere("id = :id", "id", "id123").executeBlocking().getBody();// Using query DSL builderCategoryPagedQueryResponse response = projectClient().categories().get().withWhere(CategoryQueryBuilderDsl.of().id().is("id123")).executeBlocking().getBody();
For more examples of Querydsl in the v2 SDK, see the query tests.
Accessing Attribute values
To access Attributes with the correct type and avoid type casting, use AttributeAccessor
with the correct type.
final String attributeValue = product.getMasterData().getStaged().getMasterVariant().getAttribute("test").getValueAsString();
final String attributeValue = product.getMasterData().getStaged().getMasterVariant().getAttribute("products").withAttribute(AttributeAccessor::asString);
For more examples of using AttributeAccessor
in the v2 SDK, see the Attribute tests.
Compatibility layer for Java v1 SDK
The Java v2 SDK introduced breaking changes to the SDK client configuration. The commercetools-sdk-compat-v1 compatibility layer module allows you to use the v2 SDK in conjunction with the v1 SDK, enabling you to simplify the migration process.
When you use the compatibility layer, the v1 SDK adapts its internal logic, so you don't need to change your whole business logic. Use this flexibility to gradually migrate to the v2 SDK.
Using Requests from the Java v1 SDK
The CompatClient can 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 {@Testpublic 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 Java v2 SDK
The CompatSphereClient acts as a replacement SphereClient for applications using the v1 SDK.
public class CompatSphereClientUsageTest {@Testpublic 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);}}