

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

# 控制属性转换
<a name="ddb-en-client-adv-features-conversion"></a>

默认情况下，表架构通过 `[AttributeConverterProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverterProvider.html)` 接口的默认实现为许多常见的 Java 类型提供转换器。您可以使用自定义 `AttributeConverterProvider` 实现来更改整体默认行为。您还可以更改单个属性的转换器。

有关可用转换器的列表，请参阅[AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html)接口 Java 文档。

## 提供自定义属性转换器提供程序
<a name="ddb-en-client-adv-features-conversion-prov"></a>

您可以通过 `@DynamoDbBean` `(converterProviders = {…})` 注释提供单个 `AttributeConverterProvider` 或一个有序的 `AttributeConverterProvider` 链。任何自定义 `AttributeConverterProvider` 都必须扩展 `AttributeConverterProvider` 接口。

请注意，如果您提供自己的属性转换器提供程序链，则将覆盖默认的转换器提供程序 `DefaultAttributeConverterProvider`。如果您要使用 `DefaultAttributeConverterProvider` 的功能，必须将其包含在链中。

也可以用空 `{}` 数组对 Bean 进行注释。这将禁用任何属性转换器提供程序，包括默认提供程序。在这种情况下，所有要映射的属性都必须有自己的属性转换器。

以下代码段显示了单个转换器提供程序。

```
@DynamoDbBean(converterProviders = ConverterProvider1.class)
public class Customer {

}
```

以下代码段显示了转换器提供程序链的用法。由于 SDK 默认转换器排在最后，因此它的优先级最低。

```
@DynamoDbBean(converterProviders = {
   ConverterProvider1.class, 
   ConverterProvider2.class,
   DefaultAttributeConverterProvider.class})
public class Customer {

}
```

静态表架构生成器有一种工作方式与此相同的 `attributeConverterProviders()` 方法。如以下代码段所示。

```
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
  StaticTableSchema.builder(Customer.class)
    .newItemSupplier(Customer::new)
    .addAttribute(String.class, a -> a.name("name")
                                     a.getter(Customer::getName)
                                     a.setter(Customer::setName))
    .attributeConverterProviders(converterProvider1, converterProvider2)
    .build();
```

## 覆盖单个属性的映射
<a name="ddb-en-client-adv-features-conversion-single"></a>

要覆盖单个属性的映射方式，请为该属性提供一个 `AttributeConverter`。此添加会覆盖表架构中由 `AttributeConverterProviders` 提供的任何转换器。这将仅为该属性添加一个自定义转换器。除非为其他属性明确指定该转换器，否则其他属性即使类型相同，也不会使用该转换器。

`@DynamoDbConvertedBy` 注释用于指定自定义 `AttributeConverter` 类，如以下代码段所示。

```
@DynamoDbBean
public class Customer {
    private String name;

    @DynamoDbConvertedBy(CustomAttributeConverter.class)
    public String getName() { return this.name; }
    public void setName(String name) { this.name = name;}
}
```

静态架构的生成器具有等效的属性生成器 `attributeConverter()` 方法。此方法采用 `AttributeConverter` 的实例，如下所示。

```
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
  StaticTableSchema.builder(Customer.class)
    .newItemSupplier(Customer::new)
    .addAttribute(String.class, a -> a.name("name")
                                     a.getter(Customer::getName)
                                     a.setter(Customer::setName)
                                     a.attributeConverter(customAttributeConverter))
    .build();
```

## 示例
<a name="ddb-en-client-adv-features-conversion-example"></a>

此示例演示一个为 [https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpCookie.html](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpCookie.html) 对象提供属性转换器的 `AttributeConverterProvider` 实现。

以下 `SimpleUser` 类包含一个名为 `lastUsedCookie` 的属性，该属性是 `HttpCookie` 的一个实例。

`@DynamoDbBean` 注释的参数列出了提供转换器的两个 `AttributeConverterProvider` 类。

------
#### [ Class with annotations ]

```
    @DynamoDbBean(converterProviders = {CookieConverterProvider.class, DefaultAttributeConverterProvider.class})
    public static final class SimpleUser {
        private String name;
        private HttpCookie lastUsedCookie;

        @DynamoDbPartitionKey
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public HttpCookie getLastUsedCookie() {
            return lastUsedCookie;
        }

        public void setLastUsedCookie(HttpCookie lastUsedCookie) {
            this.lastUsedCookie = lastUsedCookie;
        }
```

------
#### [ Static table schema ]

```
    private static final TableSchema<SimpleUser> SIMPLE_USER_TABLE_SCHEMA =
            TableSchema.builder(SimpleUser.class)
                    .newItemSupplier(SimpleUser::new)
                    .attributeConverterProviders(CookieConverterProvider.create(), AttributeConverterProvider.defaultProvider())
                    .addAttribute(String.class, a -> a.name("name")
                            .setter(SimpleUser::setName)
                            .getter(SimpleUser::getName)
                            .tags(StaticAttributeTags.primaryPartitionKey()))
                    .addAttribute(HttpCookie.class, a -> a.name("lastUsedCookie")
                            .setter(SimpleUser::setLastUsedCookie)
                            .getter(SimpleUser::getLastUsedCookie))
                    .build();
```

------

以下示例中的 `CookieConverterProvider` 提供了 `HttpCookeConverter` 的一个实例。

```
    public static final class CookieConverterProvider implements AttributeConverterProvider {
        private final Map<EnhancedType<?>, AttributeConverter<?>> converterCache = ImmutableMap.of(
                // 1. Add HttpCookieConverter to the internal cache.
                EnhancedType.of(HttpCookie.class), new HttpCookieConverter());

        public static CookieConverterProvider create() {
            return new CookieConverterProvider();
        }

        // The SDK calls this method to find out if the provider contains a AttributeConverter instance
        // for the EnhancedType<T> argument.
        @SuppressWarnings("unchecked")
        @Override
        public <T> AttributeConverter<T> converterFor(EnhancedType<T> enhancedType) {
            return (AttributeConverter<T>) converterCache.get(enhancedType);
        }
    }
```

### 代码转换
<a name="ddb-en-client-adv-features-conversion-example-code"></a>

在以下 `HttpCookieConverter` 类的 `transformFrom()` 方法中，代码接收一个 `HttpCookie` 实例并将其转换为 DynamoDB 映射，并将该映射作为属性存储。

`transformTo()` 方法接收 DynamoDB 映射参数，然后调用需要名称和值的 `HttpCookie` 构造函数。

```
    public static final class HttpCookieConverter implements AttributeConverter<HttpCookie> {

        @Override
        public AttributeValue transformFrom(HttpCookie httpCookie) {

            return AttributeValue.fromM(
            Map.of ("cookieName", AttributeValue.fromS(httpCookie.getName()),
                    "cookieValue", AttributeValue.fromS(httpCookie.getValue()))
            );
        }

        @Override
        public HttpCookie transformTo(AttributeValue attributeValue) {
            Map<String, AttributeValue> map = attributeValue.m();
            return new HttpCookie(
                    map.get("cookieName").s(),
                    map.get("cookieValue").s());
        }

        @Override
        public EnhancedType<HttpCookie> type() {
            return EnhancedType.of(HttpCookie.class);
        }

        @Override
        public AttributeValueType attributeValueType() {
            return AttributeValueType.M;
        }
    }
```