Configure DynamoDB Mapper
You configure a DynamoDbMapper by passing a configuration block when you create it. The primary configuration mechanism is interceptors, which are objects that hook into the mapper’s request pipeline to observe or modify operations as they run.
import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbMapper val mapper = DynamoDbMapper(client) { interceptors += LoggingInterceptor() }
The mapper’s built-in features (TTL and atomic counters) are themselves implemented as interceptors that are registered by default, so adding your own with += augments that default set rather than replacing it.
The request pipeline
Every mapper operation flows through a five-step pipeline:
-
Initialization: set up the operation and gather initial context.
-
Serialization: convert the high-level request (and your objects) into a low-level request (and DynamoDB items).
-
Low-level invocation: call the underlying
DynamoDbClient. -
Deserialization: convert the low-level response (and DynamoDB items) into a high-level response (and your objects).
-
Completion: finalize the high-level response or exception to return to the caller.
Hooks
An interceptor exposes hooks that run before or after pipeline steps. Hooks come in two kinds:
-
Read-only hooks observe an operation without changing it. They are useful for logging, metrics, and debugging. They run before and after each step and return nothing.
-
Modify hooks can change the request or response in flight. They run before each step and return the (possibly modified) value.
The following table lists the hooks in pipeline execution order:
| Hook | Kind | Runs |
|---|---|---|
|
|
read-only |
after Initialization |
|
|
modify |
before Serialization |
|
|
read-only |
before Serialization |
|
|
read-only |
after Serialization |
|
|
modify |
before Low-level invocation |
|
|
read-only |
before Low-level invocation |
|
|
read-only |
after Low-level invocation |
|
|
modify |
before Deserialization |
|
|
read-only |
before Deserialization |
|
|
read-only |
after Deserialization |
|
|
modify |
before Completion |
|
|
read-only |
before Completion |
All hooks have default no-op implementations, so an interceptor overrides only the hooks it needs.
Execution order
When multiple interceptors are registered, the order they appear in interceptors determines execution order:
-
For phases before the low-level invocation, hooks run in registration order.
-
For phases after the low-level invocation, hooks run in reverse registration order.
This mirrors a nested call stack: each interceptor "wraps" the ones registered after it.
Write an interceptor
Implement InterceptorAny (a type alias for an interceptor over any item, request, and response types) and override the hooks you care about. This read-only interceptor logs each operation as it enters the pipeline and just before the service call:
import aws.sdk.kotlin.hll.dynamodbmapper.items.ItemSchema import aws.sdk.kotlin.hll.dynamodbmapper.pipeline.HReqContext import aws.sdk.kotlin.hll.dynamodbmapper.pipeline.InterceptorAny import aws.sdk.kotlin.hll.dynamodbmapper.pipeline.LReqContext class LoggingInterceptor : InterceptorAny { override fun readAfterInitialization(ctx: HReqContext<Any, ItemSchema<Any>, Any>) { println("Starting operation for request: ${ctx.highLevelRequest}") } override fun readBeforeInvocation(ctx: LReqContext<Any, ItemSchema<Any>, Any, Any>) { println("Calling DynamoDB: ${ctx.lowLevelRequest}") } }
Each hook receives a context object that exposes the state available at that point in the pipeline. For example, highLevelRequest is available early on, and lowLevelRequest is available once serialization has produced it. A modify hook returns the value it wants to pass downstream (the relevant part of the context), while a read-only hook returns nothing.
Register interceptors
Add interceptors in the configuration block when creating the mapper:
val mapper = DynamoDbMapper(client) { interceptors += LoggingInterceptor() }
Using += preserves the default interceptors that power TTL and atomic counters. Assigning the interceptors list outright replaces them, which disables those built-in features. Prefer += unless you intend to remove the defaults.
Related topics
-
Built-in features (TTL, atomic counters): features implemented as default interceptors.
-
Get started with DynamoDB Mapper: creating a mapper.