Skip to content

DynamoDB Enhanced Client Polymorphic Types Support #6271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

anasatirbasa
Copy link

@anasatirbasa anasatirbasa commented Jul 17, 2025

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
    • @DynamoDbSubtypeDiscriminator to mark the discriminator field on the base type.
    • @DynamoDbSupertype (with inner Subtype annotation) to declare each concrete subtype and its discriminator value on the supertype class.
  • Static Attribute Tag
    • Added StaticAttributeTags.subtypeName() and SubtypeNameTag to record the discriminator attribute name in TableMetadata.
  • Polymorphic Schema Classes
    • StaticSubtype<T> encapsulates a subtype’s TableSchema and its discriminator value.
    • StaticPolymorphicTableSchema<T> implements TableSchema<T>: reads the discriminator from the item or object, looks up the right StaticSubtype, and delegates all mapping calls.
    • PolymorphicTableSchema<T> wraps the static polymorphic schema for recursive resolution and caching.
  • Factory Integration
    • Updated TableSchemaFactory.fromClass(...) to detect @DynamoDbSupertype and route to PolymorphicTableSchema.create(...).
  • Extension & Operation Hooks
    • Modified EnhancedClientUtils.readAndTransformSingleItem and all core operations (Put, Update, Transact) to resolve and use the concrete subtype schema before invoking extensions or building requests.
  • Converters Delegation
    • Added an override of converterForAttribute(...) in StaticPolymorphicTableSchema to delegate to the root schema so user‐defined @DynamoDbConvertedBy converters continue to work seamlessly.
  • 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 StaticPolymorphicTableSchema covering:
      • Mapping to and from each subtype (mapToItem / itemToMap).
      • Error cases: missing discriminator, invalid discriminator value, duplicate subtype names.
    • Verified that custom attribute converters (e.g. for Instant) are correctly applied via converterForAttribute.
  • Integration Tests
    • Put/get/update items in a real DynamoDB Local table with a mixed set of Person and Customer subclasses.
    • Tested with polymorphic beans and flattened maps to ensure dispatch at each level.
  • Manual Verification
    • Confirmed that client‐side extensions (e.g. auto‐timestamp update) receive the correct subtype schema context in beforeWrite / afterRead.

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

  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • 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
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2.0 license

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant