This library extends the official commercetools Java SDK by generating custom types defined in commercetools projects. Currently, type-safe product types, reference expansion and custom fields are supported.
Accessing product attributes and custom fields with the provided tools like AttributeAccessor
is not type-safe.
It has no IDE support and makes your code harder to refactor. This library aims to provide types for all your custom commercetools types.
Given a product-type like this:
{
"id": "e8de347b-38fa-401d-a996-aa118658a90f",
"name": "test",
"attributes": [
{
"name": "a-boolean",
"type": {
"name": "boolean"
}
},
{
"name": "an-enum",
"type": {
"name": "enum",
"values": []
}
},
{
"name": "ref-set",
"type": {
"name": "set",
"elementType": {
"name": "reference",
"referenceTypeId": "product"
}
}
},
{
"name": "nested-second-type",
"type": {
"name": "nested",
"typeReference": {
"typeId": "product-type",
"id": "30313b5a-8573-4d3e-bfbf-566238168505"
}
}
}
]
}
the library will generate the following classes (simplified):
class TestProduct : Product
class TestProductCatalogData : ProductCatalogData
class TestProductData : ProductData
class TestProductVariant : ProductVariant
data class TestProductVariantAttributes (
val aBoolean: Boolean?,
val anEnum: AttributePlainEnumValue?,
val refSet: Set<ProductReference>?,
val nestedSecondType: SecondTypeProductVariantAttributes?
)
Instead of dealing with attributes like this:
val product =
apiRoot.products()
.withKey("some-key")
.get()
.executeBlocking()
val productVariant =
product
.masterData
.current
.masterVariant
print(productVariant.withProductVariant(AttributesAccessor::of).asBoolean("a-boolean"))
you can now use typed attributes:
val product =
apiRoot.products()
.withKey("some-key")
.get()
.executeBlocking()
val productVariant =
product
.masterData
.current
.masterVariant
when (productVariant) {
is TestProductVariant -> print(productVariant.typedAttributes.aBoolean)
else -> …
}
Alternatively, if you know the expected type in advance, you can narrow the type like this:
val product =
apiRoot.products()
.withKey("some-key")
.get()
.executeBlocking(TestProduct::class.java)
val productVariant =
product
.masterData
.current
.masterVariant
print(productVariant.typedAttributes.aBoolean)
In order to make attribute updates more type-safe, constants for property names are generated.
ProductSetAttributeAction
.builder()
.name(TestProductVariantAttributes.A_BOOLEAN)
.value(true)
.build()
Since the library generates classes conforming to all API interfaces, you can start using it without the need to refactor all your existing code.
- generator - Code for generating type-safe custom types defined in commercetools projects
- gradle-plugin - Gradle Plugin that generates type-safe custom types
While the package generator
is published as a stand-alone library, the most common use case is generating custom types by using the Gradle Plugin.
The quickest way to generate custom types for your commercetools project is to simply download them.
To do so, generate an API client with the scopes view_types
and view_products
, and then configure the plugin like this:
import de.akii.commercetools.api.customtypes.plugin.gradle.commercetoolsCustomTypes
import com.commercetools.api.defaultconfig.ServiceRegion
plugins {
id("de.akii.commercetools.api.customtypes") version $pluginVersion
}
commercetoolsCustomTypes {
packageName = "your.types.go.here"
credentials {
clientId = "<client-id>"
clientSecret = "<client-secret>"
serviceRegion = ServiceRegion.GCP_EUROPE_WEST1
projectName = "<project-name>"
}
}
Alternatively, you can provide the types yourself. To do so, configure paths to the JSON files instead.
import de.akii.commercetools.api.customtypes.plugin.gradle.commercetoolsCustomTypes
plugins {
id("de.akii.commercetools.api.customtypes") version $pluginVersion
}
commercetoolsCustomTypes {
packageName = "your.types.go.here"
productTypes {
productTypesFile = File("./productTypes.json")
}
customFields {
typesFile = File("./types.json")
}
}
The plugin will now automatically generate custom types based on your type definitions.
Once you've generated your custom types, you can configure the official commercetools SDK API to use them.
To do so, you need to register the generated Jackson module TypedProductApiModule
and/or TypedResourcesApiModule
.
import com.commercetools.api.defaultconfig.ApiRootBuilder
import com.commercetools.api.defaultconfig.ServiceRegion
import io.vrap.rmf.base.client.ResponseSerializer
import io.vrap.rmf.base.client.oauth2.ClientCredentials
import io.vrap.rmf.base.client.utils.json.JsonUtils
import your.types.go.here.TypedProductApiModule
import your.types.go.here.TypedResourcesApiModule
val objectMapper =
JsonUtils
.createObjectMapper()
.registerModule(TypedProductApiModule())
.registerModule(TypedResourcesApiModule())
val apiRoot =
ApiRootBuilder.of()
.defaultClient(
ClientCredentials.of()
.withClientId("<client-id>")
.withClientSecret("<client-secret>")
.build(),
ServiceRegion.GCP_EUROPE_WEST1
)
.withSerializer(ResponseSerializer.of(objectMapper))
.build("<project-name>")
For alternative ways of configuring the SDK, please consult the commercetools documentation on client customization. This library introduces no breaking changes to the API.
To get started, please fork the repo and checkout a new branch. You can then build the library locally with Gradle.
./gradlew clean build
After you have your local branch set up, take a look at our open issues to see where you can contribute.
This library is licensed under the MIT license.