Flatten attributes from other classes
If the attributes for your table are spread across several different Java classes, either through inheritance or composition, the DynamoDB Enhanced Client API provides support to flatten the attributes into one class.
Use inheritance
If your classes use inheritance, use the following approaches to flatten the hierarchy.
Use annotated beans
For the annotation approach, both classes must carry the @DynamoDbBean
annotation and a class must carry one or more primary key annotations.
The following shows examples of data classes that have an inheritance relationship.
Use static schemas
For the static schema approach, use the extend()
method of the builder to
collapse the attributes of the parent class onto the child class. This is shown after
comment line 1 in the following example.
StaticTableSchema<org.example.tests.model.inheritance.stat.GenericRecord> GENERIC_RECORD_SCHEMA = StaticTableSchema.builder(org.example.tests.model.inheritance.stat.GenericRecord.class) // The partition key will be inherited by the top level mapper. .addAttribute(String.class, a -> a.name("id") .getter(org.example.tests.model.inheritance.stat.GenericRecord::getId) .setter(org.example.tests.model.inheritance.stat.GenericRecord::setId) .tags(primaryPartitionKey())) .addAttribute(String.class, a -> a.name("created_date") .getter(org.example.tests.model.inheritance.stat.GenericRecord::getCreatedDate) .setter(org.example.tests.model.inheritance.stat.GenericRecord::setCreatedDate)) .build(); StaticTableSchema<org.example.tests.model.inheritance.stat.Customer> CUSTOMER_SCHEMA = StaticTableSchema.builder(org.example.tests.model.inheritance.stat.Customer.class) .newItemSupplier(org.example.tests.model.inheritance.stat.Customer::new) .addAttribute(String.class, a -> a.name("name") .getter(org.example.tests.model.inheritance.stat.Customer::getName) .setter(org.example.tests.model.inheritance.stat.Customer::setName)) // 1. Use the extend() method to collapse the parent attributes onto the child class. .extend(GENERIC_RECORD_SCHEMA) // All the attributes of the GenericRecord schema are added to Customer. .build();
The previous static schema example uses the following data classes. Because the mapping is defined when you build the static table schema, the data classes don't require annotations.
Use composition
If your classes use composition, use the following approaches to flatten the hierarchy.
Use annotated beans
The @DynamoDbFlatten
annotation flattens the contained class.
The following data class examples use the @DynamoDbFlatten
annotation to
effectively add all attributes of the contained GenericRecord
class to the
Customer
class.
You can use the flatten annotation to flatten as many different eligible classes as you need to. The following constraints apply:
-
All attribute names must be unique after they are flattened.
-
There must never be more than one partition key, sort key, or table name.
Use static schemas
When you build a static table schema, use the flatten()
method of the
builder. You also supply the getter and setter methods that identify the contained
class.
StaticTableSchema<GenericRecord> GENERIC_RECORD_SCHEMA = StaticTableSchema.builder(GenericRecord.class) .newItemSupplier(GenericRecord::new) .addAttribute(String.class, a -> a.name("id") .getter(GenericRecord::getId) .setter(GenericRecord::setId) .tags(primaryPartitionKey())) .addAttribute(String.class, a -> a.name("created_date") .getter(GenericRecord::getCreatedDate) .setter(GenericRecord::setCreatedDate)) .build(); StaticTableSchema<Customer> CUSTOMER_SCHEMA = StaticTableSchema.builder(Customer.class) .newItemSupplier(Customer::new) .addAttribute(String.class, a -> a.name("name") .getter(Customer::getName) .setter(Customer::setName)) // Because we are flattening a component object, we supply a getter and setter so the // mapper knows how to access it. .flatten(GENERIC_RECORD_SCHEMA, Customer::getRecord, Customer::setRecord) .build();
The previous static schema example uses the following data classes.
You can use the builder pattern to flatten as many different eligible classes as you need to.
Implications for other code
When you use the @DynamoDbFlatten
attribute (or flatten()
builder method), the item in DynamoDB contains an attribute for each attribute of the composed
object. It also includes the attributes of the composing object.
In contrast, if you annotate a data class with a composed class and don't use
@DynamoDbFlatten
, the item is saved with the composed object as a single
attribute.
For example, compare the Customer
class shown in the flattening with composition
example with and without flattening of the record
attribute. You can
visualize the difference with JSON as shown in the following table.
With flattening | Without flattening |
---|---|
3 attributes | 2 attributes |
|
|
The difference becomes important if you have other code accessing the DynamoDB table that expects to find certain attributes.