From e93a2110d0afaf74e93862c5b813cd95e0805172 Mon Sep 17 00:00:00 2001 From: "Adrian D." <101290859+adev-code@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:48:24 -0700 Subject: [PATCH 1/4] Add DynamoDB Enhanced Client README example for a list of objects Add a "Store a list of objects inside an item" section that shows how to save a List of beans as a DynamoDB list of maps, with annotations (@DynamoDbBean) and with a StaticTableSchema (EnhancedType.listOf(EnhancedType.documentOf(...))). The README previously only showed flattening. Fixes #2265 --- ...-AmazonDynamoDBEnhancedClient-7929bf6.json | 6 ++ services-custom/dynamodb-enhanced/README.md | 90 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 .changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json diff --git a/.changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json b/.changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json new file mode 100644 index 000000000000..008e86f8a73f --- /dev/null +++ b/.changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json @@ -0,0 +1,6 @@ +{ + "type": "documentation", + "category": "Amazon DynamoDB Enhanced Client", + "description": "Add a README example that shows how to store a list of objects inside an item as a DynamoDB list of maps, by using annotations or a StaticTableSchema. See [#2265](https://github.com/aws/aws-sdk-java-v2/issues/2265).", + "contributor": "adev-code" +} diff --git a/services-custom/dynamodb-enhanced/README.md b/services-custom/dynamodb-enhanced/README.md index 121f42eae063..d7d721017778 100644 --- a/services-custom/dynamodb-enhanced/README.md +++ b/services-custom/dynamodb-enhanced/README.md @@ -540,6 +540,96 @@ static final TableSchema CUSTOMER_TABLE_SCHEMA = .build(); ``` +### Store a list of objects inside an item +To store a `List` of your own objects inside a single attribute, instead of +flattening their fields to the top level of the item, give the enhanced client +a schema for the nested class. Each object is saved as a map, and the attribute +is saved as a DynamoDB list of those maps (simplified): + +``` +name: "ABC" +recordMetadata: [ {id: "123", details: "hello"}, {id: "456", details: "yellow"} ] +``` + +Using annotations, annotate both classes with `@DynamoDbBean`: + +```java +import java.util.List; +import software.amazon.awssdk.enhanced.dynamodb.TableSchema; +import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; +import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; + +@DynamoDbBean +public class Customer { + private String name; + private List recordMetadata; + + @DynamoDbPartitionKey + public String getName() { return name; } + public void setName(String name) { this.name = name; } + + public List getRecordMetadata() { return recordMetadata; } + public void setRecordMetadata(List recordMetadata) { this.recordMetadata = recordMetadata; } +} + +@DynamoDbBean +public class GenericRecord { + private String id; + private String details; + + public String getId() { return id; } + public void setId(String id) { this.id = id; } + + public String getDetails() { return details; } + public void setDetails(String details) { this.details = details; } +} + +TableSchema schema = TableSchema.fromBean(Customer.class); +``` + +Using a StaticTableSchema, build a schema for the nested class and pass it to +`EnhancedType.documentOf()` inside `EnhancedType.listOf()`: + +```java +import software.amazon.awssdk.enhanced.dynamodb.EnhancedType; +import software.amazon.awssdk.enhanced.dynamodb.TableSchema; +import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags; +import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema; + +// Schema for the nested class. It has no key, so it is only used inside another schema. +static final TableSchema GENERIC_RECORD_SCHEMA = + StaticTableSchema.builder(GenericRecord.class) + .newItemSupplier(GenericRecord::new) + .addAttribute(String.class, a -> a.name("id") + .getter(GenericRecord::getId) + .setter(GenericRecord::setId)) + .addAttribute(String.class, a -> a.name("details") + .getter(GenericRecord::getDetails) + .setter(GenericRecord::setDetails)) + .build(); + +static final TableSchema CUSTOMER_TABLE_SCHEMA = + StaticTableSchema.builder(Customer.class) + .newItemSupplier(Customer::new) + .addAttribute(String.class, a -> a.name("name") + .getter(Customer::getName) + .setter(Customer::setName) + .tags(StaticAttributeTags.primaryPartitionKey())) + .addAttribute(EnhancedType.listOf( + EnhancedType.documentOf(GenericRecord.class, GENERIC_RECORD_SCHEMA)), + a -> a.name("recordMetadata") + .getter(Customer::getRecordMetadata) + .setter(Customer::setRecordMetadata)) + .build(); +``` + +Don't use `addAttribute(List.class, ...)` for this attribute. `List.class` doesn't +tell the enhanced client the element type, so building the schema fails with an +`IndexOutOfBoundsException`. + +For more examples, see [Save complex types](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-adv-features-nested.html#ddb-en-client-adv-features-nested-mapping) +in the *AWS SDK for Java 2.x Developer Guide*. + ### Flat map attributes from another class If the attributes for your table record are spread across several different Java objects, either through inheritance or composition, the From caf8541618f08764bf3b336d3664e073b3e87101 Mon Sep 17 00:00:00 2001 From: "Adrian D." <101290859+adev-code@users.noreply.github.com> Date: Thu, 22 Oct 2026 13:12:25 -0700 Subject: [PATCH 2/4] Update services-custom/dynamodb-enhanced/README.md Co-authored-by: Kenneth Daily --- services-custom/dynamodb-enhanced/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services-custom/dynamodb-enhanced/README.md b/services-custom/dynamodb-enhanced/README.md index d7d721017778..10e567c094ff 100644 --- a/services-custom/dynamodb-enhanced/README.md +++ b/services-custom/dynamodb-enhanced/README.md @@ -542,8 +542,7 @@ static final TableSchema CUSTOMER_TABLE_SCHEMA = ### Store a list of objects inside an item To store a `List` of your own objects inside a single attribute, instead of -flattening their fields to the top level of the item, give the enhanced client -a schema for the nested class. Each object is saved as a map, and the attribute +flattening their fields to the top level of the item, pass a schema for the nested class to the enhanced client. Each object is saved as a map, and the attribute is saved as a DynamoDB list of those maps (simplified): ``` From 88149c21d9497a0258e1492ee3c3db7dc704ea8b Mon Sep 17 00:00:00 2001 From: "Adrian D." <101290859+adev-code@users.noreply.github.com> Date: Thu, 22 Oct 2026 13:25:36 -0700 Subject: [PATCH 3/4] Clarify list-of-objects intro in DynamoDB Enhanced Client README --- services-custom/dynamodb-enhanced/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services-custom/dynamodb-enhanced/README.md b/services-custom/dynamodb-enhanced/README.md index 10e567c094ff..6cc3ccb23296 100644 --- a/services-custom/dynamodb-enhanced/README.md +++ b/services-custom/dynamodb-enhanced/README.md @@ -541,9 +541,11 @@ static final TableSchema CUSTOMER_TABLE_SCHEMA = ``` ### Store a list of objects inside an item -To store a `List` of your own objects inside a single attribute, instead of -flattening their fields to the top level of the item, pass a schema for the nested class to the enhanced client. Each object is saved as a map, and the attribute -is saved as a DynamoDB list of those maps (simplified): +To store a `List` of your own objects inside a single attribute, pass a schema +for the nested class to the enhanced client. Each object is saved as a map, and +the attribute is saved as a DynamoDB list of those maps. The stored item looks +like this (shown without DynamoDB's type labels, such as `L` for list and `M` +for map): ``` name: "ABC" From 4eb872e42e689c372f825694ec77ab533aa5c8a3 Mon Sep 17 00:00:00 2001 From: "Adrian D." <101290859+adev-code@users.noreply.github.com> Date: Thu, 22 Oct 2026 16:24:39 -0700 Subject: [PATCH 4/4] Add immutable classes note and remove changelog entry --- .../documentation-AmazonDynamoDBEnhancedClient-7929bf6.json | 6 ------ services-custom/dynamodb-enhanced/README.md | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 .changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json diff --git a/.changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json b/.changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json deleted file mode 100644 index 008e86f8a73f..000000000000 --- a/.changes/next-release/documentation-AmazonDynamoDBEnhancedClient-7929bf6.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "documentation", - "category": "Amazon DynamoDB Enhanced Client", - "description": "Add a README example that shows how to store a list of objects inside an item as a DynamoDB list of maps, by using annotations or a StaticTableSchema. See [#2265](https://github.com/aws/aws-sdk-java-v2/issues/2265).", - "contributor": "adev-code" -} diff --git a/services-custom/dynamodb-enhanced/README.md b/services-custom/dynamodb-enhanced/README.md index 6cc3ccb23296..97553ce07f4b 100644 --- a/services-custom/dynamodb-enhanced/README.md +++ b/services-custom/dynamodb-enhanced/README.md @@ -628,6 +628,11 @@ Don't use `addAttribute(List.class, ...)` for this attribute. `List.class` doesn tell the enhanced client the element type, so building the schema fails with an `IndexOutOfBoundsException`. +If your classes are immutable, annotate both classes with `@DynamoDbImmutable` +and build the schema with `TableSchema.fromImmutableClass(...)`. The list is +stored the same way. For details, see +[Working with immutable data classes](#working-with-immutable-data-classes). + For more examples, see [Save complex types](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-adv-features-nested.html#ddb-en-client-adv-features-nested-mapping) in the *AWS SDK for Java 2.x Developer Guide*.