-
Notifications
You must be signed in to change notification settings - Fork 856
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
DynamoDB Enhanced Client support for Immutable objects #1801
Comments
So, I have a work-in-progress POC going on. It has ended up looking like this:
I have been able to successfully implement 'extend' to work with an abstract immutable tableschema as long as it has a builder that is a superclass of the child builder. This is not completely intuitive to someone building these data classes, but this is how I accomplished it on the other side :
Anyone have a better idea how we should support abstract immutables? Does anyone care? :) |
Would be nice if this can support records (when they get finalized) |
@ntkoopman Can you explain what you mean? |
So I had everything working in my POC except 'flatten'. Everything up to this point had been relatively straight forward once I grasped the idea of introducing a second (builder) class and the notion of type-asymmetry between mapping to an object and mapping from an object, however 'flatten' was implemented in a way that undermined that type-asymmetry as it needed to both read the nested object and mutate it as it converted a new flattened attribute. There was just no way to extend this same approach to work in the world of immutables so a complete rethink was necessary. The good news is I have it working, this time instead of flattening and transforming the setters of individual attributes, the entire flattened tableschema is captured in a tree and there is something akin to a routing table for attributes so when it is translating it knows which attributes belong to a 'sub' table-schema and collects them all together and then delegates the translation entirely to that table-schema. The added benefit here is that any type of TableSchema can be nested (eg: have a flattened StaticTableSchema within an ImmutableTableSchema). This is a big win, so I have decided to go ahead with the third phase of the refactor:- The third phase of the immutables refactor is to get StaticTableSchema to actually use the ImmutableTableSchema. What the StaticTableSchema does can now be described as a simplified variant of the ImmutableTableSchema where the builder type is the same as the item type and the 'build' action is essentially a no-op. In my head this works, will be putting it into practice later and hoping all the tests still pass. |
By the way if anyone wants to see what I'm upto here or play with the POC themselves and give immutable mapped objects a whirl, just check out this branch : https://github.com/aws/aws-sdk-java-v2/tree/bmaizels/ddbenhanced-immutables-poc |
I'm talking about https://openjdk.java.net/jeps/384 which is currently a preview feature in Java 14 |
@bmaizels I cloned your POC and found it was straight forward to switch my lambda project from using BeanTableSchema to use the ImmutableTableSchema. I only needed to define the schema, build and all tests passed! Just a few pieces of feedback from my experience:
@Value.Style(
builder = "new",
defaults = @Value.Immutable(copy = false),
visibility = Value.Style.ImplementationVisibility.PACKAGE,
builderVisibility = Value.Style.BuilderVisibility.PACKAGE,
jdkOnly = true,
overshadowImplementation = true
)
@Value.Immutable
@JsonSerialize(as = Customer.class)
@JsonDeserialize(builder = Customer.Builder.class)
public interface Customer {
String getAccountId();
// ... snip
String getName();
class Builder extends ImmutableCustomer.Builder {
}
static Builder builder() {
return new Builder();
}
static TableSchema<Customer> tableSchema() {
return ImmutableTableSchema.builder(Customer.class, Customer.Builder.class)
.newItemBuilder(Customer::builder, Customer.Builder::build)
.addAttribute(String.class, a -> a.name("accountId")
.getter(Customer::getAccountId)
.setter(Customer.Builder::accountId)
.tags(primaryPartitionKey()))
// ... snip
.addAttribute(String.class, a -> a.name("name")
.getter(Customer::getName)
.setter(Customer.Builder::name)
.tags(secondaryPartitionKey("customers_by_name")))
.build();
}
} Also somewhat related to my last comment, I have experimented with using an |
One thing I'd be interested to see is support for immutable Kotlin classes. These classes expose a single public constructor with each property, and no builder class. Today declaration of beans is wonderfully simple: @DynamoDbBean
class DynamoEvent(
@get:DynamoDbPartitionKey
var objectId: UUID,
@get:DynamoDbSortKey
var version: Long,
var created: Instant,
// etc.
) "Immutable support" in this context would mean changing each For reference, and I don't know exactly how it's been implemented or if it would be helpful, Jackson's Kotlin module does a good job for our other mapping use cases to immutable objects. |
Good news immutables fans! I found some time to finish up what I started here, and now have a feature preview branch that includes all the functionality I originally wanted to deliver for immutables including an annotated class version with introspection that can be used interchangably with the existing DynamoDb beans (you can have an immutable as a document inside a bean for example!). Please have a look and tell me what you think. I'll be working to release this as soon as possible. |
This feature is now merged! Please give it a try and let us know what you think. |
Hi, |
This issue represents the desire for the DynamoDB Enhanced Client to be able to support Java idiomatic immutable data classes for mapping purposes. At time of writing only mutable 'bean'-like classes with standard getters and setters are supported.
Full support for immutables would likely include :
The text was updated successfully, but these errors were encountered: