Changes in the DynamoDB mapping/document APIs from version 1 to version 2 - Amazon SDK for Java 2.x
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Changes in the DynamoDB mapping/document APIs from version 1 to version 2

This topic details the changes in the Java SDK's high-level APIs for Amazon DynamoDB from version 1.x (v1) to the Amazon SDK for Java 2.x (v2). We first cover the object-to-table mapping API and then discuss the document API for working with JSON-style documents.

High-level changes

The names of the mapping client in each library differ in v1 and v2:

  • v1 - DynamoDBMapper

  • v2 - DynamoDB Enhanced Client

You interact with the two libraries in much the same way: you instantiate a mapper/client and then supply a Java POJO to APIs that read and write these items to DynamoDB tables. Both libraries also offer annotations for the class of the POJO to direct how the client handles the POJO.

Notable differences when you move to v2 include:

  • V2 and v1 use different method names for the low-level DynamoDB operations. For example:

    v1 v2
    load getItem
    save putItem
    batchLoad batchGetItem
  • V2 offers multiple ways to define table schemas and map POJOs to tables. You can choose from the use of annotations or a schema generated from code using a builder. V2 also offers mutable and immutable versions of schemas.

  • With v2, you specifically create the table schema as one of the first steps, whereas in v1, the table schema is inferred from the annotated class as needed.

  • V2 includes the Document API client in the enhanced client API, whereas v1 uses a separate API.

  • All APIs are available in synchronous and asynchronous versions in v2.

See the DynamoDB mapping section in this guide for more detailed information on the v2 enhanced client.

Import dependencies

v1 v2
<dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> <version>1.X.X</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-dynamodb</artifactId> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.X.X*</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>dynamodb-enhanced</artifactId> </dependency> </dependencies>

* Latest version.

In v1, a single dependency includes both the low-level DynamoDB API and the mapping/document API, whereas in v2, you use the dynamodb-enhanced artifact dependency to access the mapping/document API. The dynamodb-enhanced module contains a transitive dependency on the low-level dynamodb module.

API changes

Create a client

Use case v1 v2

Normal instantiation

AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(Regions.US_EAST_1) .build(); DynamoDBMapper mapper = new DynamoDBMapper(standardClient);
DynamoDbClient standardClient = DynamoDbClient.builder() .credentialsProvider(ProfileCredentialsProvider.create()) .region(Region.US_EAST_1) .build(); DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(standardClient) .build();

Minimal instantiation

AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard(); DynamoDBMapper mapper = new DynamoDBMapper(standardClient);
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();

With attribute transformer*

DynamoDBMapper mapper = new DynamoDBMapper(standardClient, attributeTransformerInstance);
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(standardClient) .extensions(extensionAInstance, extensionBInstance) .build();

*Extensions in v2 correspond roughly to attribute transformers in v1. The Use extensions 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

@DynamoDBTable(tableName ="Customer") public class Customer { ... }
DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));

Map to a DynamoDB secondary index

  1. Define a POJO class that represents the index.

    • Annotate class with the @DynamoDBTable supplying the name of the table that has the index.

    • Annotate properties with @DynamoDBIndexHashKey and optionally @DynamoDBIndexRangeKey.

  2. Create a query expression.

  3. Query using reference to the POJO class that represents the index. For example

    mapper.query(IdEmailIndex.class, queryExpression)

    where IdEmailIndex is the mapping class for the index.

The section in the DynamoDB Developer Guide that discusses the v1 query method shows a complete example.

  1. Annotate attributes of a POJO class with @DynamoDbSecondaryPartitionKey (for a GSI) and @DynamoDbSecondarySortKey (for and GSI or LSI). For example,

    @DynamoDbSecondarySortKey(indexNames = "IdEmailIndex") public String getEmail() { return this.email; }
  2. Retrieve a reference to the index. For example,

    DynamoDbIndex<Customer> customerIndex = customerTable.index("IdEmailIndex");
  3. Query the index.

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, the table 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)

The table shows the commonly used forms:

mapper.load(item) mapper.load(item, config)
Table operations
Use case v1 DynamoDB operation v2

Write a Java POJO to a DynamoDB table

mapper.save(item) mapper.save(item, config) mapper.save(item, saveExpression, config)

In v1, DynamoDBMapperConfig.SaveBehavior and annotations determines which low-level DynamoDB method will be called. In general, UpdateItem is called except when using SaveBehavior.CLOBBER and SaveBehavior.PUT. Auto-generated keys are a special use case, and occasionally both PutItem and UpdateItem are used.

PutItem, UpdateItem
table.putItem(putItemRequest) table.putItem(item) table.putItemWithResponse(item) //Returns metadata. updateItem(updateItemRequest) table.updateItem(item) table.updateItemWithResponse(item) //Returns metadata.
Read an item from a DynamoDB table to a Java POJO
mapper.load(item) mapper.load(item, config)
GetItem
table.getItem(getItemRequest) table.getItem(item) table.getItem(key) table.getItemWithResponse(key) //Returns POJO with metadata.
Delete an item from a DynamoDB table
mapper.delete(item, deleteExpression, config)
DeleteItem
table.deleteItem(deleteItemRequest) table.deleteItem(item) table.deleteItem(key)
Query a DynamoDB table or secondary index and return a paginated list
mapper.query(Customer.class, queryExpression) mapper.query(Customer.class, queryExpression, mapperConfig)
Query
table.query(queryRequest) table.query(queryConditional)

Use the returned PageIterable.stream() (lazy loading) for sync responses and PagePublisher.subscribe() for async responses

Query a DynamoDB table or secondary index and return a list
mapper.queryPage(Customer.class, queryExpression) mapper.queryPage(Customer.class, queryExpression, mapperConfig)
Query
table.query(queryRequest) table.query(queryConditional)

Use the returned PageIterable.items() (lazy loading) for sync responses and PagePublisher.items.subscribe() for async responses

Scan a DynamoDB table or secondary index and return a paginated list
mapper.scan(Customer.class, scanExpression) mapper.scan(Customer.class, scanExpression, mapperConfig)
Scan
table.scan() table.scan(scanRequest)

Use the returned PageIterable.stream() (lazy loading) for sync responses and PagePublisher.subscribe() for async responses

Scan a DynamoDB table or secondary index and return a list
mapper.scanPage(Customer.class, scanExpression) mapper.scanPage(Customer.class, scanExpression, mapperConfig)
Scan
table.scan() table.scan(scanRequest)

Use the returned PageIterable.items() (lazy loading) for sync responses and PagePublisher.items.subscribe() for async responses

Read multiple items from multiple tables in a batch
mapper.batchLoad(Arrays.asList(customer1, customer2, book1)) mapper.batchLoad(itemsToGet) // itemsToGet: Map<Class<?>, List<KeyPair>>
BatchGetItem
enhancedClient.batchGetItem(batchGetItemRequest) enhancedClient.batchGetItem(r -> r.readBatches( ReadBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addGetItem(i -> i.key(k -> k.partitionValue(0))) .build(), ReadBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addGetItem(i -> i.key(k -> k.partitionValue(0))) .build())) // Iterate over pages with lazy loading or over all items from the same table.
Write multiple items to multiple tables in a batch
mapper.batchSave(Arrays.asList(customer1, customer2, book1))
BatchWriteItem
enhancedClient.batchWriteItem(batchWriteItemRequest) enhancedClient.batchWriteItem(r -> r.writeBatches( WriteBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addPutItem(item1) .build(), WriteBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addPutItem(item2) .build()))
Delete multiple items from multiple tables in a batch
mapper.batchDelete(Arrays.asList(customer1, customer2, book1))
BatchWriteItem
enhancedClient.batchWriteItem(r -> r.writeBatches( WriteBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addDeleteItem(item1key) .build(), WriteBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addDeleteItem(item2key) .build()))
Write/delete multiple items in a batch
mapper.batchWrite(Arrays.asList(customer1, book1), Arrays.asList(customer2))
BatchWriteItem
enhancedClient.batchWriteItem(r -> r.writeBatches( WriteBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addPutItem(item1) .build(), WriteBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addDeleteItem(item2key) .build()))
Carry out a transactional write
mapper.transactionWrite(transactionWriteRequest)
TransactWriteItems
enhancedClient.transactWriteItems(transasctWriteItemsRequest)
Carry out a transactional read
mapper.transactionLoad(transactionLoadRequest)
TransactGetItems
enhancedClient.transactGetItems(transactGetItemsRequest)
Get count of matching items of a scan or query
mapper.count(Customer.class, queryExpression) mapper.count(Customer.class, scanExpression)
Query, Scan with Select.COUNT Not supported
Create a table in DynamoDB corresponding to the POJO class
mapper.generateCreateTableRequest(Customer.class)

The previous statement generates a low-level create table request; users must call createTable on the DynamoDB client.

CreateTable
table.createTable(createTableRequest) table.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput()) .globalSecondaryIndices( EnhancedGlobalSecondaryIndex.builder() .indexName("gsi_1") .projection(p -> p.projectionType(ProjectionType.ALL)) .provisionedThroughput(getDefaultProvisionedThroughput()) .build()));
Perform a parallel scan in DynamoDB
mapper.parallelScan(Customer.class, scanExpression, numTotalSegments)
Scan with Segment and TotalSegments parameters

Users are required to handle the worker threads and call scan for each segment:

table.scan(r -> r.segment(0).totalSegments(5))
Integrate Amazon S3 with DynamoDB to store intelligent S3 links
mapper.createS3Link(bucket, key) mapper.getS3ClientCache()
-

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
@DynamoDBTable (tableName ="CustomerTable")
@DynamoDbBean @DynamoDbBean(converterProviders = {...})
The table name is defined when calling the DynamoDbEDnhancedClient#table() method.
Designate a class member as a table attribute
@DynamoDBAttribute(attributeName = "customerName")
@DynamoDbAttribute("customerName")
Designate a class member is a hash/partition key
@DynamoDBHashKey
@DynamoDbPartitionKey
Designate a class member is a range/sort key
@DynamoDBHashKey
@DynamoDbSortKey
Designate a class member is a secondary index hash/partition key
@DynamoDBIndexHashKey
@DynamoDbSecondaryPartitionKey
Designate a class member is a secondary index range/sort key
@DynamoDBIndexRangeKey
@DynamoDbSecondarySortKey
Ignore this class member when mapping to a table
@DynamoDBIgnore
@DynamoDbIgnore
Designate a class member as an auto-generated UUID key attribute
@DynamoDBAutoGeneratedKey
@DynamoDbAutoGeneratedUuid

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
@DynamoDBAutoGeneratedTimestamp
@DynamoDbAutoGeneratedTimestampAttribute

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
@DynamoDBVersionAttribute
@DynamoDbVersionAttribute

The extension that provides this is auto-loaded.

Designate a class member as requiring a custom conversion
@DynamoDBTypeConverted
@DynamoDbConvertedBy
Designate a class member to be stored as a different attribute type
@DynamoDBTyped(<DynamoDBAttributeType>)
No equivalent
Designate a class that can be serialized to a DynamoDB document (JSON-style document) or sub-document
@DynamoDBDocument
No direct equivalent annotation. Use the Enhanced Document API.

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
@DynamoDbIgnoreNulls
Designate a class member to be an empty object if all attributes are null N/A
@DynamoDbPreserveEmptyObject
Designate special update action for a class member N/A
@DynamoDbUpdateBehavior
Designate an immutable class N/A
@DynamoDbImmutable
Designate a class member as an auto-incremented counter attribute N/A
@DynamoDbAtomicCounter

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
DynamoDBMapperConfig.builder()
Batch load retry strategy
.withBatchLoadRetryStrategy(batchLoadRetryStrategy)
retry failed items
Batch write retry strategy
.withBatchWriteRetryStrategy(batchWriteRetryStrategy)
retry failed items
Consistent reads
.withConsistentReads(CONSISTENT)
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
.withConversionSchema(conversionSchema)

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
.withObjectTableNameResolver() .withTableNameOverride() .withTableNameResolver()

Static implementations provide backwards compatibility with older versions

use annotation or guess from class

The table name is defined when calling the DynamoDbEDnhancedClient#table() method.

Pagination load strategy
.withPaginationLoadingStrategy(strategy)

Options are: LAZY_LOADING, EAGER_LOADING, or ITERATION_ONLY

LAZY_LOADING

Iteration only is the default. The other v1 options are not supported.

Request metric collection
.withRequestMetricCollector(collector)
null Use metricPublisher() in ClientOverrideConfiguration when building the standard DynamoDB client.
Save behavior
.withSaveBehavior(SaveBehavior.CLOBBER)

Options are UPDATE, CLOBBER, PUT, APPEND_SET, or UPDATE_SKIP_NULL_ATTRIBUTES.

UPDATE

In v2, you call putItem() or updateItem() explicitly.

CLOBBER or PUT: Corresponding action in v 2 is calling putItem(). There is no specific CLOBBER configuration.

UPDATE: Corresponds to updateItem()

UPDATE_SKIP_NULL_ATTRIBUTES: Corresponds to updateItem(). Control update behavior with the request setting ignoreNulls and the annotation/tag DynamoDbUpdateBehavior.

APPEND_SET: Not supported

Type converter factory
.withTypeConverterFactory(typeConverterFactory)
standard type converters

Set on the bean by using

@DynamoDbBean(converterProviders = {ConverterProvider.class, DefaultAttributeConverterProvider.class})

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()
new DynamoDBSaveExpression() .withExpected(Collections.singletonMap( "otherAttribute", new ExpectedAttributeValue(false))) .withConditionalOperator(ConditionalOperator.AND);
Deprecated; use ConditionExpression instead.
Condition expression delete()
deleteExpression.setConditionExpression("zipcode = :zipcode") deleteExpression.setExpressionAttributeValues(...)
Expression conditionExpression = Expression.builder() .expression("#key = :value OR #key1 = :value1") .putExpressionName("#key", "attribute") .putExpressionName("#key1", "attribute3") .putExpressionValue(":value", AttributeValues.stringValue("wrong")) .putExpressionValue(":value1", AttributeValues.stringValue("three")) .build(); DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder() .conditionExpression(conditionExpression).build();
Filter expression query(), scan()
scanExpression .withFilterExpression("#statename = :state") .withExpressionAttributeValues(attributeValueMapBuilder.build()) .withExpressionAttributeNames(attributeNameMapBuilder.build())
Map<String, AttributeValue> values = singletonMap(":key", stringValue("value")); Expression filterExpression = Expression.builder() .expression("name = :key") .expressionValues(values) .build(); QueryEnhancedRequest request = QueryEnhancedRequest.builder() .filterExpression(filterExpression).build();
Condition expression for query query()
queryExpression.withKeyConditionExpression()
QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b .partitionValue("movie01")); QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder() .queryConditional(keyEqual) .build();

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 API reference.

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 AttributeConverterProviders. 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.

Document API

The Document API supports working with JSON-style documents as single items in a DynamoDB table. The v1 Document API has a corresponding API in v2, but instead of using a separate client for the document API as in v1, v2 incorporates document API features in the DynamoDB enhanced client.

In v1, the Item class represents an unstructured record from a DynamoDB table. In v2, an unstructured record is represented by an instance of the EnhancedDocument class. Note that primary keys are defined in the table schema for v2, and on the item itself in v1.

The table below compares the differences between the Document APIs in v1 and v2.

Use case v1 v2
Create a document client
AmazonDynamoDB client = ... //Create a client. DynamoDB documentClient = new DynamoDB(client);
// The v2 Document API uses the same DynamoDbEnhancedClient // that is used for mapping POJOs. DynamoDbClient standardClient = ... //Create a standard client. DynamoDbEnhancedClient enhancedClient = ... // Create an enhanced client.
Reference a table
Table documentTable = docClient.documentClient("Person");
DynamoDbTable<EnhancedDocument> documentTable = enhancedClient.table("Person", TableSchema.documentSchemaBuilder() .addIndexPartitionKey(TableMetadata.primaryIndexName(),"id", AttributeValueType.S) .attributeConverterProviders(AttributeConverterProvider.defaultProvider()) .build());
Work with semi-structured data
Put item
Item item = new Item() .withPrimaryKey("id", 50) .withString("firstName", "Shirley"); PutItemOutcome outcome = documentTable.putItem(item);
EnhancedDocument personDocument = EnhancedDocument.builder() .putNumber("id", 50) .putString("firstName", "Shirley") .build(); documentTable.putItem(personDocument);
Get item
GetItemOutcome outcome = documentTable.getItemOutcome( "id", 50); Item personDocFromDb = outcome.getItem(); String firstName = personDocFromDb.getString("firstName");
EnhancedDocument personDocFromDb = documentTable .getItem(Key.builder() .partitionValue(50) .build()); String firstName = personDocFromDb.getString("firstName");
Work with JSON items
Convert a JSON structure to use it with the Document API
// The 'jsonPerson' identifier is a JSON string. Item item = new Item().fromJSON(jsonPerson);
// The 'jsonPerson' identifier is a JSON string. EnhancedDocument document = EnhancedDocument.builder() .json(jsonPerson).build());
Put JSON
documentTable.putItem(item)
documentTable.putItem(document);
Read JSON
GetItemOutcome outcome = //Get item. String jsonPerson = outcome.getItem().toJSON();
String jsonPerson = documentTable.getItem(Key.builder() .partitionValue(50).build()) .fromJson();

API reference and guides for document APIs

v1 v2
API reference Javadoc Javadoc
Documentation guide Amazon DynamoDB Developer Guide Enhanced Document API (this guide)

FAQ

Q. Does optimistic locking with a version number work the same way in v2 as in v1?

A. The behavior is similar, but v2 does not does not automatically add conditions for the delete operations. You must add condition expressions manually if you want to control the delete behavior.