Skip to content

Commit 3af1858

Browse files
committed
DynamoDB Enhanced Client Polymorphic Types Support
1 parent 0770c1c commit 3af1858

File tree

1 file changed

+39
-65
lines changed

1 file changed

+39
-65
lines changed

services-custom/dynamodb-enhanced/README.md

Lines changed: 39 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -688,82 +688,56 @@ builder pattern.
688688

689689

690690

691+
## Polymorphic Types Support
691692

692-
### Using subtypes to assist with single-table design
693-
It's considered a best practice in some situations to combine entities of various types into a single table in DynamoDb
694-
to enable the querying of multiple related entities without the need to actually join data across multiple tables. The
695-
enhanced client assists with this by supporting polymorphic mapping into distinct subtypes.
693+
The Enhanced Client now supports **polymorphic type hierarchies**, allowing multiple subclasses to be stored in the same table.
696694

697-
Let's say you have a customer:
695+
### Usage Example: Person Hierarchy
698696

699697
```java
700-
public class Customer {
701-
String getCustomerId();
702-
void setId(String id);
703-
704-
String getName();
705-
void setName(String name);
706-
}
707-
```
708-
709-
And an order that's associated with a customer:
710-
711-
```java
712-
public class Order {
713-
String getOrderId();
714-
void setOrderId();
715-
716-
String getCustomerId();
717-
void setCustomerId();
718-
}
719-
```
720-
721-
You could choose to store both of these in a single table that is indexed by customer ID, and create a TableSchema that
722-
is capable of mapping both types of entities into a common supertype:
723-
724-
```java
725-
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
726-
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
727-
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSubtypeDiscriminator;
728-
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSupertype;
729-
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSupertype.Subtype;
730-
731698
@DynamoDbBean
732-
@DynamoDbSupertype({
733-
@Subtype(discriminatorValue = "CUSTOMER", subtypeClass = Customer.class),
734-
@Subtype(discriminatorValue = "ORDER", subtypeClass = Order.class)})
735-
public class CustomerRelatedEntity {
736-
@DynamoDbSubtypeDiscriminator
737-
String getEntityType();
738-
void setEntityType();
739-
740-
@DynamoDbPartitionKey
741-
String getCustomerId();
742-
void setCustomerId();
743-
}
699+
@DynamoDbSupertype(
700+
value = {
701+
@DynamoDbSupertype.Subtype(discriminatorValue = "EMPLOYEE", subtypeClass = Employee.class),
702+
@DynamoDbSupertype.Subtype(discriminatorValue = "CUSTOMER", subtypeClass = Customer.class)
703+
},
704+
discriminatorAttributeName = "discriminatorType" // optional, defaults to "type"
705+
)
706+
public class Person {}
744707

745708
@DynamoDbBean
746-
public class Customer extends CustomerRelatedEntity {
747-
String getName();
748-
void setName(String name);
709+
public class Employee extends Person {
710+
private String employeeId;
711+
public String getEmployeeId() { return employeeId; }
712+
public void setEmployeeId(String id) { this.employeeId = id; }
749713
}
750714

751715
@DynamoDbBean
752-
public class Order extends CustomerRelatedEntity {
753-
String getOrderId();
754-
void setOrderId();
716+
public class Customer extends Person {
717+
private String customerId;
718+
public String getCustomerId() { return customerId; }
719+
public void setCustomerId(String id) { this.customerId = id; }
755720
}
756721
```
757722

758-
Now all you have to do is create a TableSchema that maps the supertype class:
723+
**Notes:**
724+
- By default, the discriminator attribute is `"type"` unless overridden.
725+
726+
### Static/Immutable Schema Support
727+
728+
Polymorphism works for both **bean-style** and **immutable/builder-based** classes.
729+
759730
```java
760-
TableSchema<CustomerRelatedEntity> tableSchema = TableSchema.fromClass(CustomerRelatedEntity.class);
761-
```
762-
Now you have a `TableSchema` that can map any objects of both `Customer` and `Order` and write them to the table,
763-
and can also read any record from the table and correctly instantiate it using the subtype class. So it's now possible
764-
to write a single query that will return both the customer record and all order records associated with a specific
765-
customer ID.
766-
767-
As with all the other `TableSchema` implementations, a static version is provided that allows reflective introspection
768-
to be skipped entirely and is recommended for applications where cold-start latency is critical. See the javadocs for
769-
`StaticPolymorphicTableSchema` for an example of how to use this.
731+
// Obtain schema for Person hierarchy
732+
TableSchema<Person> schema = TableSchema.fromClass(Person.class);
733+
734+
// Serialize Employee → DynamoDB item
735+
Employee e = new Employee();
736+
e.setEmployeeId("E123");
737+
Map<String, AttributeValue> item = schema.itemToMap(e, false);
738+
// → {"employeeId":"E123", "discriminatorType":"EMPLOYEE"}
739+
740+
// Deserialize back
741+
Person restored = schema.mapToItem(item);
742+
// → returns Employee instance
743+
```

0 commit comments

Comments
 (0)