You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无注解DynamoDBTypeConverter适配不可变FooBar类问题

我刚好碰到过类似的不可变类与DynamoDB映射的场景,你的需求完全可以通过指定Map<String, AttributeValue>作为转换器的目标类型来解决——这正是DynamoDB底层用来表示属性结构的原生类型,完美匹配你存储的格式。

第一步:实现正确的DynamoDBTypeConverter

我们需要把FooBar和DynamoDB原生的AttributeValue结构做双向转换,转换器的类型参数应该定义为DynamoDBTypeConverter<Map<String, AttributeValue>, FooBar>。具体实现如下:

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConverter;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import java.util.HashMap;
import java.util.Map;

public class FooBarConverter implements DynamoDBTypeConverter<Map<String, AttributeValue>, FooBar> {

    @Override
    public Map<String, AttributeValue> convert(FooBar fooBar) {
        Map<String, AttributeValue> attributeMap = new HashMap<>();
        // 将int值转换为DynamoDB要求的数字类型(N类型)
        attributeMap.put("foo", new AttributeValue().withN(String.valueOf(fooBar.getFoo())));
        attributeMap.put("bar", new AttributeValue().withN(String.valueOf(fooBar.getBar())));
        return attributeMap;
    }

    @Override
    public FooBar unconvert(Map<String, AttributeValue> attributeMap) {
        // 从AttributeValue中提取数字字符串,转成int后构造不可变的FooBar实例
        int foo = Integer.parseInt(attributeMap.get("foo").getN());
        int bar = Integer.parseInt(attributeMap.get("bar").getN());
        return new FooBar(foo, bar);
    }
}

第二步:在表实体类中关联转换器

因为不能给FooBar本身添加注解,我们需要在包含FooBar字段的表实体类上,给对应的getter方法添加@DynamoDBTypeConverted注解来指定转换器。如果你的实体类也是不可变的,记得给构造方法加上@DynamoDBConstructor注解,让DynamoDBMapper能正确实例化它:

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBConstructor;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConverted;

@DynamoDBTable(tableName = "YourTargetTable")
public class TableEntity {
    private final String id;
    private final FooBar fooBar;

    @DynamoDBConstructor
    public TableEntity(String id, FooBar fooBar) {
        this.id = id;
        this.fooBar = fooBar;
    }

    @DynamoDBHashKey
    public String getId() {
        return id;
    }

    @DynamoDBTypeConverted(converter = FooBarConverter.class)
    public FooBar getFooBar() {
        return fooBar;
    }
}

第三步:使用DynamoDBMapper读写数据

现在就可以正常用映射器进行读写操作了,完全不需要修改FooBar的不可变结构:

// 初始化客户端和映射器
AmazonDynamoDB dynamoDBClient = AmazonDynamoDBClientBuilder.defaultClient();
DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);

// 写入数据
FooBar fooBar = new FooBar(45, 12);
TableEntity entity = new TableEntity("item-001", fooBar);
mapper.save(entity);

// 读取数据
TableEntity retrievedEntity = mapper.load(TableEntity.class, "item-001");
System.out.println(retrievedEntity.getFooBar().getFoo()); // 输出45
System.out.println(retrievedEntity.getFooBar().getBar()); // 输出12

为什么之前的尝试失败?

  • 普通Map类型:你用的应该是Map<String, Object>,DynamoDB无法自动将这种通用Map转换成它的原生属性结构,必须明确使用Map<String, AttributeValue>才能匹配底层存储格式。
  • String类型:DynamoDB会把字符串当成单一属性值存储,而你的数据是两个独立的属性(foo和bar),所以读取时自然拿不到正确的内容。
  • Object类型:DynamoDB无法解析无明确类型信息的Object转换目标,所以会抛出类型解析异常。

内容的提问来源于stack exchange,提问作者Paul Davies

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 16:47:50