使用不可变数据类 - AWS SDK for Java 2.x

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用不可变数据类

DynamoDB 增强型客户端 API 的映射功能适用于不可变的数据类。不可变类只有 getter,且需要一个生成器类,使 SDK 可用来创建该类的实例。不可变类不像 Customer 类那样使用 @DynamoDbBean 注释,而是使用 @DynamoDbImmutable 注释,该注释采用一个指示要使用的生成器类的参数。

以下类是 Customer 的不可变版本。

package org.example.tests.model.immutable; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey; import java.time.Instant; @DynamoDbImmutable(builder = CustomerImmutable.Builder.class) public class CustomerImmutable { private final String id; private final String name; private final String email; private final Instant regDate; private CustomerImmutable(Builder b) { this.id = b.id; this.email = b.email; this.name = b.name; this.regDate = b.regDate; } // This method will be automatically discovered and used by the TableSchema. public static Builder builder() { return new Builder(); } @DynamoDbPartitionKey public String id() { return this.id; } @DynamoDbSortKey public String email() { return this.email; } @DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name") public String name() { return this.name; } @DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"}) public Instant regDate() { return this.regDate; } public static final class Builder { private String id; private String email; private String name; private Instant regDate; // The private Builder constructor is visible to the enclosing Customer class. private Builder() {} public Builder id(String accountId) { this.id = id; return this; } public Builder email(String email) { this.email = email; return this; } public Builder name(String name) { this.name = name; return this; } public Builder regDate(Instant regDate) { this.regDate = regDate; return this; } // This method will be automatically discovered and used by the TableSchema. public CustomerImmutable build() { return new CustomerImmutable(this); } } }

使用 @DynamoDbImmutable 注释数据类时,您必须满足以下要求。

  1. 每个既不覆盖 Object.class 又未使用 @DynamoDbIgnore 注释的方法都必须是 DynamoDB 表属性的 getter。

  2. 每个 getter 在生成器类上都必须有一个对应的区分大小写的 setter。

  3. 必须仅满足以下任一构造条件。

    • 生成器类必须具有公共默认构造函数。

    • 数据类必须有一个名为 builder() 的公共静态方法,该方法不带任何参数并返回生成器类的实例。此选项显示在不可变 Customer 类中。

  4. 生成器类必须有一个名为 build() 的公共方法,该方法不带任何参数并返回不可变类的实例。

要为不可变类创建 TableSchema,请使用 TableSchema 上的 fromImmutableClass() 方法,如以下代码段所示。

static final TableSchema<CustomerImmutable> customerImmutableTableSchema = TableSchema.fromImmutableClass(CustomerImmutable.class);

就像您可以从可变类创建 DynamoDB 表一样,您也可以通过一次性 调用 DynamoDbTablecreateTable() 从不可变类创建该表,如以下代码段示例所示。

static void createTableFromImmutable(DynamoDbEnhancedClient enhancedClient, String tableName, DynamoDbWaiter waiter){ // First, create an in-memory representation of the table using the 'table()' method of the DynamoDb Enhanced Client. // 'table()' accepts a name for the table and a TableSchema instance that you created previously. DynamoDbTable<CustomerImmutable> customerDynamoDbTable = enhancedClient .table(tableName, TableSchema.fromImmutableClass(CustomerImmutable.class)); // Second, call the 'createTable()' method on the DynamoDbTable instance. customerDynamoDbTable.createTable(); waiter.waitUntilTableExists(b -> b.tableName(tableName)); }

使用第三方库,例如 Lombok

第三方库(例如 Project Lombok)可帮助生成与不可变对象关联的样板代码。只要数据类遵循本部分详述的约定,DynamoDB 增强型客户端 API 就可以与这些库结合使用。

以下示例演示带有 Lombok 注释的不可变 CustomerImmutable 类。请注意 Lombok 的 onMethod 功能是如何将基于属性的 DynamoDB 注释(例如 @DynamoDbPartitionKey)复制到生成的代码中的。

@Value @Builder @DynamoDbImmutable(builder = Customer.CustomerBuilder.class) public class Customer { @Getter(onMethod_=@DynamoDbPartitionKey) private String id; @Getter(onMethod_=@DynamoDbSortKey) private String email; @Getter(onMethod_=@DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name")) private String name; @Getter(onMethod_=@DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"})) private Instant createdDate; }