aws-sdk-java-v2
aws-sdk-java-v2 copied to clipboard
DynamoDB Enhanced - support for custom AttributeConverters and StringConverters to be used in collections
Added support for custom AttributeConverters and StringConverters in collection types
Motivation and Context
Currently, serializing custom types within collections (like List<CustomType>, Set<CustomType>, Map<CustomType, Value> or Map<Value, CustomType>) requires extensive boilerplate or duplication of internal SDK logic. The default converter providers do not support registering custom converters, making it difficult to handle these cases cleanly.
This change introduces fallback mechanisms and Jackson-based generic converters to simplify serialization of custom types in collections, improving extensibility and developer experience.
Fixes: #4862
Modifications
-
Added
GenericObjectStringConverter<T>: A generic StringConverter that uses Jackson's ObjectMapper to serialize/deserialize custom types to and from JSON strings. -
Added
FallbackAttributeConverter<T>: Wraps a StringConverter<T> to enable its use in collections (lists, sets, maps) when no specific AttributeConverter is registered. -
Added
FallbackStringConverterProvider: A custom StringConverterProvider that first tries the default provider and falls back to GenericObjectStringConverter using ObjectMapper when needed. -
Enabled support for custom types in collections: Collection element types and map keys/values can now be serialized/deserialized using fallback converters.
-
Added tests: Unit and integration tests verifying support for custom object types in List, Set, and Map structures.
Testing
-
Unit Tests: Verified the behavior of
GenericObjectStringConverter,FallbackAttributeConverter, andFallbackStringConverterProvider, ensuring correct serialization and deserialization of custom types. -
Integration Tests: correct serialization/deserialization of: - List of elements of custom type - Set of elements of custom type - Map with key of custom type - Map with values of custom type
-
Edge Cases: Tested null values, empty collections, and malformed input strings to ensure robustness.
Test Coverage Checklist
| Scenario | Done | Comments if Not Done |
|---|---|---|
| 1. Different TableSchema Creation Methods | ||
| a. TableSchema.fromBean(Customer.class) | [x] | |
| b. TableSchema.fromImmutableClass(Customer.class) for immutable classes | [x] | |
| c. TableSchema.documentSchemaBuilder().build() | [ ] | |
| d. StaticTableSchema.builder(Customer.class) | [x] | |
| 2. Nesting of Different TableSchema Types | ||
| a. @DynamoDbBean with nested @DynamoDbBean as NonNull | [x] | |
| b. @DynamoDbBean with nested @DynamoDbImmutable as NonNull | [x] | |
| c. @DynamoDbImmutable with nested @DynamoDbBean as NonNull | [x] | |
| d. @DynamoDbBean with nested @DynamoDbBean as Null | [x] | |
| e. @DynamoDbBean with nested @DynamoDbImmutable as Null | [x] | |
| f. @DynamoDbImmutable with nested @DynamoDbBean as Null | [x] | |
| 3. CRUD Operations | ||
| a. scan() | [ ] | |
| b. query() | [x] | |
| c. updateItem() | [ ] | |
| d. putItem() | [x] | |
| e. getItem() | [x] | |
| f. deleteItem() | [ ] | |
| g. batchGetItem() | [ ] | |
| h. batchWriteItem() | [ ] | |
| i. transactGetItems() | [ ] | |
| j. transactWriteItems() | [ ] | |
| 4. Data Types and Null Handling | ||
| a. top-level null attributes | [x] | |
| b. collections with null elements | [x] | |
| c. maps with null values | [x] | |
| d. conversion between null Java values and AttributeValue | [x] | |
| e. full serialization/deserialization cycle with null values | [x] | |
| 5. AsyncTable and SyncTable | ||
| a. DynamoDbAsyncTable Testing | [ ] | |
| b. DynamoDbTable Testing | [ ] | |
| 6. New/Modification in Extensions | ||
| a. Tables with Scenario in ScenarioSl No.1 (All table schemas are Must) | [ ] | |
| b. Test with Default Values in Annotations | [ ] | |
| c. Combination of Annotation and Builder passes extension | [ ] | |
| 7. New/Modification in Converters | ||
| a. Tables with Scenario in ScenarioSl No.1 (All table schemas are Must) | [ ] | |
| b. Test with Default Values in Annotations | [ ] | |
| c. Test All Scenarios from 1 to 5 | [ ] |
Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
Checklist
- [x] I have read the CONTRIBUTING document
- [x] Local run of
mvn installsucceeds - [x] My code follows the code style of this project
- [ ] My change requires a change to the Javadoc documentation
- [ ] I have updated the Javadoc documentation accordingly
- [x] I have added tests to cover my changes
- [x] All new and existing tests passed
- [x] I have added a changelog entry. Adding a new entry must be accomplished by running the
scripts/new-changescript and following the instructions. Commit the new file created by the script in.changes/next-releasewith your changes. - [ ] My change is to implement 1.11 parity feature and I have updated LaunchChangelog
License
- [x] I confirm that this pull request can be released under the Apache 2 license