aws-sdk-java-v2
aws-sdk-java-v2 copied to clipboard
DynamoDB Enhanced Client Polymorphic Types Support
Motivation and Context
By default, the DynamoDbEnhancedClient does not natively support storing multiple Java subclasses of a common supertype in the same table. In complex domain models (e.g. storing both Employee and Customer instances of Person), there was a need to write complex type‐discrimination logic. This change introduces a clean, annotation‐driven layer that automatically dispatches to the correct subtype schema at runtime, reducing boilerplate and eliminating fragile manual checks.
Modifications
-
New Annotations
-
@DynamoDbSubtypeDiscriminatorto mark the discriminator field on the base type. -
@DynamoDbSupertype(with innerSubtypeannotation) to declare each concrete subtype and its discriminator value on the supertype class.
-
-
Static Attribute Tag
- Added
StaticAttributeTags.subtypeName()andSubtypeNameTagto record the discriminator attribute name inTableMetadata.
- Added
-
Polymorphic Schema Classes
-
StaticSubtype<T>encapsulates a subtype’sTableSchemaand its discriminator value. -
StaticPolymorphicTableSchema<T>implementsTableSchema<T>: reads the discriminator from the item or object, looks up the rightStaticSubtype, and delegates all mapping calls. -
PolymorphicTableSchema<T>wraps the static polymorphic schema for recursive resolution and caching.
-
-
Factory Integration
- Updated
TableSchemaFactory.fromClass(...)to detect@DynamoDbSupertypeand route toPolymorphicTableSchema.create(...).
- Updated
-
Extension & Operation Hooks
- Modified
EnhancedClientUtils.readAndTransformSingleItemand all core operations (Put, Update, Transact) to resolve and use the concrete subtype schema before invoking extensions or building requests.
- Modified
-
Converters Delegation
- Added an override of
converterForAttribute(...)inStaticPolymorphicTableSchemato delegate to the root schema so user‐defined@DynamoDbConvertedByconverters continue to work seamlessly.
- Added an override of
-
Diagrams & Documentation
- Added a Low Level Design document including sequence diagrams and flowcharts to illustrate routing logic and serialization/deserialization flows.
Testing
-
Unit Tests
- Added tests for
StaticPolymorphicTableSchemacovering:- Mapping to and from each subtype (
mapToItem/itemToMap). - Error cases: missing discriminator, invalid discriminator value, duplicate subtype names.
- Mapping to and from each subtype (
- Verified that custom attribute converters (e.g. for
Instant) are correctly applied viaconverterForAttribute.
- Added tests for
-
Integration Tests
- Put/get/update items in a real DynamoDB Local table with a mixed set of
PersonandCustomersubclasses. - Tested with polymorphic beans and flattened maps to ensure dispatch at each level.
- Put/get/update items in a real DynamoDB Local table with a mixed set of
-
Manual Verification
- Confirmed that client‐side extensions (e.g. auto‐timestamp update) receive the correct subtype schema context in
beforeWrite/afterRead.
- Confirmed that client‐side extensions (e.g. auto‐timestamp update) receive the correct subtype schema context in
Screenshots (if appropriate)
(See design doc diagrams in Section 4 and 5 for visual routing and flowchart illustrations.)
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
- [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
- [x] I have updated the Javadoc documentation accordingly
- [x] I have added tests to cover my changes
- [x] All new and existing tests passed
- [ ] I have added a changelog entry. Adding a new entry must be accomplished by running the
scripts/new-changescript and following the instructions. - [ ] 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.0 license