Generate a schema from annotations
The simplest way to use DynamoDB Mapper is to annotate your Kotlin classes and let the SDK generate their schemas for you at build time. You annotate a class with @DynamoDbItem, mark its key properties, and the schema-generator Gradle plugin inspects the annotated classes and emits a schema object and a convenience extension function for obtaining a typed table.
This topic covers the plugin setup, the available annotations, custom converters for unsupported types, and how to configure the generator. For the complete list of annotations and their parameters, see the annotations reference.
Note
The schema-generator plugin is available for Gradle only. If you use Maven, see Manually define schemas for how to define schemas in code.
How annotation-based generation works
-
You apply the schema-generator plugin and annotate your data classes.
-
At build time, the plugin’s symbol processor reads the annotations. For each
@DynamoDbItemclassFoo, the plugin generates aFooSchemaobject and aDynamoDbMapper.getFooTable(…)extension function. -
Your code calls the generated extension or passes the generated schema to
getTableto obtain a typedTableand perform operations on it.
You never need to write or edit the generated code. Rebuilding your project regenerates it from your annotated classes.
Add the plugin and dependencies
Apply the plugin and add the runtime and annotations dependencies in your build.gradle.kts. Replace X.Y.Z with the latest release of the SDK
// build.gradle.kts val sdkVersion = "[.replaceable]##X.Y.Z##" plugins { id("aws.sdk.kotlin.hll.dynamodbmapper.schema.generator") version sdkVersion } dependencies { implementation("aws.sdk.kotlin:dynamodb-mapper:$sdkVersion") implementation("aws.sdk.kotlin:dynamodb-mapper-annotations:$sdkVersion") }
Each of these dependencies fulfills a different function:
-
The
dynamodbmapper.schema.generatorplugin generates the schemas -
The
dynamodb-mapperdependency provides theDynamoDbMappertype -
The
dynamodb-mapper-annotationsdependency provides the annotations you apply to your classes
Annotate a class
Annotate the class with @DynamoDbItem and mark its primary key. Every top-level item type must have exactly one partition key (@DynamoDbPartitionKey) and can have at most one sort key (@DynamoDbSortKey). All other public properties are mapped to attributes automatically.
import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbItem import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbPartitionKey import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbSortKey import aws.smithy.kotlin.runtime.time.Instant @DynamoDbItem data class Order( @DynamoDbPartitionKey val customerId: String, @DynamoDbSortKey val orderId: String, val status: OrderStatus, val totalCents: Long, val productSkus: List<String>, val tags: Set<String>, val placedAt: Instant, )
The generator maps the property types it knows about, including primitives, String, enums such as OrderStatus, collections, and several SDK runtime types such as Instant. For types it doesn’t support out of the box, supply a custom converter.
Supported types
The following Kotlin types are automatically converted by DynamoDB Mapper into the given DynamoDB types:
| Kotlin type | DynamoDB type | Notes |
|---|---|---|
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
|
Values in the map use the converter appropriate for their type |
|
|
||
|
|
|
Stored as the enum constant’s |
|
|
||
|
|
|
Stored as epoch seconds by default |
|
|
||
|
|
|
Elements in the list use the converter appropriate for their type |
|
|
||
|
|
|
Values in the map use the converter appropriate for their type |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
|
|
|
Any supported type |
|
Customize how properties map
Several property-level annotations can adjust the default mapping. For example:
import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbAttribute import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbAttributeConverter import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbIgnore import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbItem import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbPartitionKey import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbSortKey import aws.smithy.kotlin.runtime.time.Instant import kotlin.uuid.Uuid @DynamoDbItem data class Order( @DynamoDbPartitionKey val customerId: String, @DynamoDbSortKey val orderId: String, val status: OrderStatus, val totalCents: Long, val productSkus: List<String>, val tags: Set<String>, @DynamoDbAttribute("created_at") val placedAt: Instant, @DynamoDbAttributeConverter(UuidConverter::class) val idempotencyKey: Uuid, ) { @DynamoDbIgnore val isLargeOrder: Boolean get() = totalCents >= 100_00 }
In alphabetical order, the attribute-level annotations used in the preceding example are:
-
@DynamoDbAttribute(name): store the property under a different DynamoDB attribute name (here,placedAtis stored ascreated_at). Without it, the attribute name matches the property name. -
@DynamoDbAttributeConverter(converter): supply a customValueConverterfor a property whose type the generator doesn’t support on its own. See Convert unsupported types. -
@DynamoDbIgnore: exclude a property from mapping entirely (here, a computed convenience property).
More property annotations enable various features and are covered in-depth in DynamoDB Mapper annotations reference.
Convert unsupported types
For a property whose type the generator doesn’t natively map (for example, kotlin.uuid.Uuid), apply @DynamoDbAttributeConverter with a ValueConverter that translates between your type and a DynamoDB attribute value. A value converter implements two methods: convertRight (your type → attribute value) and convertLeft (attribute value → your type).
import aws.sdk.kotlin.hll.dynamodbmapper.values.ValueConverter import aws.sdk.kotlin.services.dynamodb.model.AttributeValue import kotlin.uuid.Uuid object UuidConverter : ValueConverter<Uuid> { override fun convertRight(from: Uuid): AttributeValue = AttributeValue.S(from.toString()) override fun convertLeft(from: AttributeValue): Uuid = Uuid.parse(from.asS()) }
The class passed to @DynamoDbAttributeConverter(…) must implement ValueConverter. See Manually define schemas for the full converter model and the built-in converters you can reuse.
Use the generated schema
After you build the project, the generator produces an OrderSchema object and, by default, a getOrderTable extension on DynamoDbMapper. Note that the extension name contains the class name Order, while the string you pass is your actual table name "orders":
val ordersTable = mapper.getOrderTable("orders")
Equivalently, pass the generated schema to getTable. By default, the generated schema lives in a package derived from your class’s package plus .dynamodbmapper.generatedschemas. For instance, if your annotated class is com.example.store.model.Order then the default generated schema is com.example.store.model.dynamodbmapper.generatedschemas.OrderSchema:
import com.example.store.model.dynamodbmapper.generatedschemas.OrderSchema val ordersTable = mapper.getTable("orders", OrderSchema)
Configure the generator
The plugin contributes a dynamoDbMapper extension to your build script. All settings are optional; their defaults are shown in the following example.
// build.gradle.kts import aws.sdk.kotlin.hll.codegen.rendering.Visibility import aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.DestinationPackage import aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.GenerateBuilderClasses dynamoDbMapper { // When to generate builder classes for your item types: WHEN_REQUIRED (default) or ALWAYS. generateBuilderClasses = GenerateBuilderClasses.WHEN_REQUIRED // Visibility of generated declarations. Default: PUBLIC. visibility = Visibility.PUBLIC // Where generated code is placed. Relative(...) (default) appends to each class's own package; // Absolute(...) places everything in one fixed package. destinationPackage = DestinationPackage.Relative("dynamodbmapper.generatedschemas") // Whether to generate the DynamoDbMapper.get<Class>Table() convenience extensions. Default: true. generateGetTableExtension = true }
The configurable settings, in alphabetical order:
| Setting | Type | Default | Purpose |
|---|---|---|---|
|
|
|
|
Package for generated code. Use |
|
|
|
|
|
|
|
|
|
Whether to generate the |
|
|
|
|
Visibility of generated declarations. |
Related topics
-
Manually define schemas: define schemas in code instead of with annotations.
-
DynamoDB Mapper annotations reference: every annotation and its parameters.
-
Built-in features (TTL, atomic counters): runtime behavior of
@DynamoDbCounterand@DynamoDbTtlSeconds.