Changes in the DynamoDB mapping APIs between version 1 and version 2 of the SDK for Java
Create a client
Use case | V1 | V2 |
---|---|---|
Normal instantiation |
|
|
Minimal instantiation |
|
|
With attribute transformer* |
|
|
*Extensions in V2 correspond roughly to attribute transformers in V1. The Use extensions to customize DynamoDB Enhanced Client operations section contains more information on extensions in V2.
Establish mapping to DynamoDB table/index
In V1, you specify a DynamoDB table name through a bean annotation. In V2, a factory
method, table()
, produces an instance of DynamoDbTable
that
represents the remote DynamoDB table. The first parameter of the table()
method is the DynamoDB table name.
Use case | V1 | V2 |
---|---|---|
Map the Java POJO class to the DynamoDB table |
|
|
Map to a DynamoDB secondary index |
The section in the DynamoDB Developer Guide that discusses the V1 |
The Use secondary indices section in this guide provides more information. |
Table operations
This section describes operation APIs that differ between V1 and V2 for most standard use cases.
In V2, all operations that involve a single table are called on the
DynamoDbTable
instance, not on the enhanced client. The enhanced
client contains methods that can target multiple tables.
In the table named Table operations below, a
POJO instance is referred to as item
or as a specific type such as
customer1
. For the V2 examples the instances named,
table
is the result of previously calling
enhancedClient.table()
that returns a reference to the
DynamoDbTable
instance.
Note that most V2 operations can be called with a fluent consumer pattern even when not shown. For example,
Customer customer = table.getItem(r → r.key(key));
or
Customer customer = table.getItem(r → r.key(k -> k.partitionValue("id").sortValue("email")))
For V1 operations, Table operations (below)
contains some of the commonly used forms and not all overloaded forms. For example,
the load()
method has the following overloads:
mapper.load(Customer.class, hashKey)
mapper.load(Customer.class, hashKey, rangeKey)
mapper.load(Customer.class, hashKey, config)
mapper.load(Customer.class, hashKey, rangeKey, config)
mapper.load(item)
mapper.load(item, config)
Table operations (below) shows the commonly used forms:
mapper.load(item) mapper.load(item, config)
Use case | V1 | V2 |
---|---|---|
Write a Java POJO to a DynamoDB table DynamoDB operation:
|
In V1, |
|
Read an item from a DynamoDB table to a Java POJO DynamoDB operation:
|
|
|
Delete an item from a DynamoDB table DynamoDB operation:
|
|
|
Query a DynamoDB table or secondary index and return a paginated list DynamoDB operation:
|
|
Use the returned |
Query a DynamoDB table or secondary index and return a list DynamoDB operation:
|
|
Use the returned |
Scan a DynamoDB table or secondary index and return a paginated list DynamoDB operation:
|
|
Use the returned |
Scan a DynamoDB table or secondary index and return a list DynamoDB operation:
|
|
Use the returned |
Read multiple items from multiple tables in a batch DynamoDB operation:
|
|
|
Write multiple items to multiple tables in a batch DynamoDB operation:
|
|
|
Delete multiple items from multiple tables in a batch DynamoDB operation:
|
|
|
Write/delete multiple items in a batch DynamoDB operation:
|
|
|
Carry out a transactional write DynamoDB operation:
|
|
|
Carry out a transactional read DynamoDB operation:
|
|
|
Get a count of matching items of a query DynamoDB operation:
|
|
|
Get a count of matching items of a scan DynamoDB
operation: |
|
|
Create a table in DynamoDB corresponding to the POJO class DynamoDB operation:
|
The previous statement generates a low-level create table request;
users must call |
|
Perform a parallel scan in DynamoDB DynamoDB operation:
|
|
Users are required to handle the worker threads and call
|
Integrate Amazon S3 with DynamoDB to store intelligent S3 links |
|
Not supported because it couples Amazon S3 and DynamoDB. |
Map classes and properties
In both V1 and V2, you map classes to tables using bean-style annotations. V2 also offers other ways to define schemas for specific use cases, such as working with immutable classes.
Bean annotations
The following table shows the equivalent bean annotations for a specific use
case that are used in V1 and V2. A Customer
class scenario is used to
illustrate parameters.
Annotations—as well as classes and enumerations—in V2 follow camel case convention and use 'DynamoDb', not 'DynamoDB'.
Use case | V1 | V2 |
---|---|---|
Map class to table |
|
The table name
is defined when calling the
DynamoDbEnhancedClient#table() method. |
Designate a class member as a table attribute |
|
|
Designate a class member is a hash/partition key |
|
|
Designate a class member is a range/sort key |
|
|
Designate a class member is a secondary index hash/partition key |
|
|
Designate a class member is a secondary index range/sort key |
|
|
Ignore this class member when mapping to a table |
|
|
Designate a class member as an auto-generated UUID key attribute |
|
The extension that provides this is not loaded by default; you must add the extension to client builder. |
Designate a class member as an auto-generated timestamp attribute |
|
The extension that provides this is not loaded by default; you must add the extension to client builder. |
Designate a class member as an auto-incremented version attribute |
|
The extension that provides this is auto-loaded. |
Designate a class member as requiring a custom conversion |
|
|
Designate a class member to be stored as a different attribute type |
|
Use an |
Designate a class that can be serialized to a DynamoDB document (JSON-style document) or sub-document |
|
Use the Enhanced Document API. See the following resources:
|
V2 additional annotations
Use case | V1 | V2 |
---|---|---|
Designate a class member not to be stored as a NULL attribute if the Java value is null | N/A |
|
Designate a class member to be an empty object if all attributes are null | N/A |
|
Designate special update action for a class member | N/A |
|
Designate an immutable class | N/A |
|
Designate a class member as an auto-incremented counter attribute | N/A |
The extension that provides this functionality is auto-loaded. |
Configuration
In V1, you generally control specific behaviors by using an instance of
DynamoDBMapperConfig
. You can supply the configuration object either
when you create the mapper or when you make a request. In V2, configuration is
specific to the request object for the operation.
Use case | V1 | Default in V1 | V2 |
---|---|---|---|
|
|||
Batch load/write retry strategy |
|
retry failed items | Configure the retry strategy on the underlying
DynamoDBClient . See Configure retry behavior in the Amazon SDK for Java 2.x in
this guide. |
Consistent reads |
|
EVENTUAL |
By default, consistent reads is false for read operations. Override
with .consistentRead(true) on the request object. |
Conversion schema with sets of marshallers/unmarshallers |
Static implementations provide backwards compatibility with older versions. |
V2_COMPATIBLE |
Not applicable. This is a legacy feature that refers to how the earliest versions of DynamoDB (V1) stored data types, and this behavior will not be preserved in the enhanced client. An example of behavior in DynamoDB V1 is storing booleans as Number instead of as Boolean. |
Table names |
Static implementations provide backwards compatibility with older versions |
use annotation or guess from class |
The table name is defined when calling the
|
Pagination load strategy |
Options are: LAZY_ |
LAZY_LOADING |
|
Request metric collection |
|
null |
Use metricPublisher() in
ClientOverrideConfiguration when building the standard
DynamoDB client. |
Save behavior |
Options are |
UPDATE |
In V2, you call
|
Type converter factory |
|
standard type converters |
Set on the bean by using
|
Per-operation configuration
In V1, some operations, such as query()
, are highly configurable
through an “expression” object submitted to the operation. For example:
DynamoDBQueryExpression<Customer> emailBwQueryExpr = new DynamoDBQueryExpression<Customer>() .withRangeKeyCondition("Email", new Condition() .withComparisonOperator(ComparisonOperator.BEGINS_WITH) .withAttributeValueList( new AttributeValue().withS("my"))); mapper.query(Customer.class, emailBwQueryExpr);
In V2, instead of using a configuration object, you set parameters on the request object by using a builder. For example:
QueryEnhancedRequest emailBw = QueryEnhancedRequest.builder() .queryConditional(QueryConditional .sortBeginsWith(kb -> kb .sortValue("my"))).build(); customerTable.query(emailBw);
Conditionals
In V2, conditional and filtering expressions are expressed using an
Expression
object, which encapsulates the condition and the mapping
of names and filters.
Use case | Operations | V1 | V2 |
---|---|---|---|
Expected attribute conditions | save(), delete(), query(), scan() |
|
Deprecated; use ConditionExpression instead. |
Condition expression | delete() |
|
|
Filter expression | query(), scan() |
|
|
Condition expression for query | query() |
|
|
Type conversion
Default converters
In V2, the SDK provides a set of default converters for all common types. You
can change type converters both at the overall provider level as well as for a
single attribute. You can find a list of the available converters in the AttributeConverter
Set a custom converter for an attribute
In V1, you can annotate a getter method with
@DynamoDBTypeConverted
to specify the class that converts between
the Java attribute type and a DynamoDB attribute type. For instance, a
CurrencyFormatConverter
that converts between a Java
Currency
type and DynamoDB String can be applied as shown in the
following snippet.
@DynamoDBTypeConverted(converter = CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
The V2 equivalent of the previous snippet is shown below.
@DynamoDbConvertedBy(CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
Note
In V1, you can apply the annotation to the attribute itself , a type or a user-defined annotation, V2 supports applying the annotation it only to the getter.
Add a type converter factory or provider
In V1, you can provide your own set of type converters, or override the types
you care about by adding a type converter factory to the configuration. The type
converter factory extends DynamoDBTypeConverterFactory
, and overrides
are done by getting a reference to the default set and extending it. The following
snippet demonstrates how to do this.
DynamoDBTypeConverterFactory typeConverterFactory =
DynamoDBTypeConverterFactory.standard().override()
.with(String.class, CustomBoolean.class, new DynamoDBTypeConverter<String, CustomBoolean>() {
@Override
public String convert(CustomBoolean bool) {
return String.valueOf(bool.getValue());
}
@Override
public CustomBoolean unconvert(String string) {
return new CustomBoolean(Boolean.valueOf(string));
}}).build();
DynamoDBMapperConfig config =
DynamoDBMapperConfig.builder()
.withTypeConverterFactory(typeConverterFactory)
.build();
DynamoDBMapper mapperWithTypeConverterFactory = new DynamoDBMapper(dynamo, config);
V2 provides similar functionality through the @DynamoDbBean
annotation. You can provide a single AttributeConverterProvider
or a
chain of ordered AttributeConverterProvider
s. Note that if you supply
your own chain of attribute converter providers, you will override the default
converter provider and must include it in the chain to use its attribute
converters.
@DynamoDbBean(converterProviders = {
ConverterProvider1.class,
ConverterProvider2.class,
DefaultAttributeConverterProvider.class})
public class Customer {
...
}
The section on attribute conversion in this guide contains a complete example for V2.