英文:
DynamoDBTypeConverter for DynamoDB document field without annotations
问题
我在DynamoDB中有一些条目,其中一个字段如下,在DynamoDB文档格式中:
`{ "foo" : { "N" : "45" }, "bar" : { "N" : "12" }}`
我有一个代表文档类型的Java类:
public class FooBar {
private final int foo;
private final int bar;
public FooBar(
int foo,
int bar
) {
this.foo = foo;
this.bar = bar;
}
public int getFoo() {
return foo;
}
public int getBar() {
return bar;
}
}
我想使用[DynamoDB映射器][1]从表中获取和插入行(代表整行的中间类因篇幅而省略)。我不想向`FooBar`类添加DynamoDB注释(`@DynamoDBDocument`、`@DynamoDBAttribute`等),因为它们需要零参数构造函数和setter方法,但这应该是一个不可变的数据对象。
因此,我想使用[DynamoDBTypeConverter][2](如[此处][3]所述)来编写自己的转换,但我找不到合适的“源”类型(替换`[?]`):
```java
class FooBarConverter implements DynamoDBTypeConverter<[?], FooBar> {
@Override
public [?] convert(FooBar object) {
...
}
@Override
public FooBar unconvert([?] object) {
...
}
}
- Map,似乎是最自然的,但会出现
DynamoDBMappingException: not supported; requires @DynamoDBTyped or @DynamoDBTypeConverted
错误 - String,似乎是一个合理的默认值,不会出错,但提供给
convert()
方法的字符串始终为空 - Object,似乎是一个万能类型,但Dynamo不支持,会出现
DynamoDBMappingException: could not resolve type of class FooBarConverter
错误
如果我们将Java类和存储格式都视为不可修改,有什么解决方案?
<details>
<summary>英文:</summary>
I have some entries in DynamoDB, which have an field as follows, in DynamoDB document format:
`{ "foo" : { "N" : "45" }, "bar" : { "N" : "12" }}`
I've got a Java class representing the document type:
public class FooBar {
private final int foo;
private final int bar;
public FooBar(
int foo,
int bar
) {
this.foo = foo;
this.bar = bar;
}
public int getFoo() {
return foo;
}
public int getBar() {
return bar;
}
}
I'd like to use a [DynamoDB mapper][1] to get and put rows to the table (the intermediate class representing the entire row is omitted for brevity). I don't want to add the DynamoDB annotations (`@DynamoDBDocument`, `@DynamoDBAttribute` etc) to the `FooBar` class as they require a zero-argument constructor and setter methods but this should be an immutable data object.
Therefore, I'd like to use a [DynamoDBTypeConverter][2] (as described [here][3]) to write my own conversion, but I cannot find a suitable 'source' type (to replace `[?]`):
class FooBarConverter implements DynamoDBTypeConverter<[?], FooBar> {
@Override
public [?] convert(FooBar object) {
...
}
@Override
public FooBar unconvert([?] object) {
...
}
}
- Map, which would seem the most natural, fails with `DynamoDBMappingException: not supported; requires @DynamoDBTyped or @DynamoDBTypeConverted`
- String, which would seem to be a reasonable default, doesn't error but the string supplied to the `convert()` method is always empty
- Object, which would seem to be a catch-all, isn't supported by Dynamo and fails with `DynamoDBMappingException: could not resolve type of class FooBarConverter`
If we regard both the Java class and the storage format as being unmodifiable, what solution is there?
[1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.html
[2]: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBTypeConverter.html
[3]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.ArbitraryDataMapping.html
</details>
# 答案1
**得分**: 5
我找到了适合作为源类型使用的类型 - [`AttributeValue`][1]。以下是转换器:
```java
public class FooBarConverter implements DynamoDBTypeConverter<AttributeValue, FooBar> {
@Override
public AttributeValue convert(FooBar object) {
return new AttributeValue()
.addMEntry("foo", new AttributeValue().withN(Integer.toString(object.getFoo())))
.addMEntry("bar", new AttributeValue().withN(Integer.toString(object.getBar())));
}
@Override
public FooBar unconvert(AttributeValue object) {
Map<String, AttributeValue> objectM = object.getM();
int foo = Integer.parseInt(objectM.get("foo").getN());
int bar = Integer.parseInt(objectM.get("bar").getN());
return new FooBar(foo, bar);
}
}
此外,以下是用于在 Dynamo 中表示整行的类:
public class FooBarRow {
private String key;
private FooBar fooBar;
public FooBarRow(
String key,
FooBar fooBar
) {
this.key = key;
this.fooBar = fooBar;
}
public FooBarRow() {
}
@DynamoDBHashKey
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@DynamoDBTypeConverted(converter = FooBarConverter.class)
public FooBar getFooBar() {
return fooBar;
}
public void setFooBar(FooBar fooBar) {
this.fooBar = fooBar;
}
}
现在,使用 DynamoDBMapper
来保存和加载 FooBarRow
实例运行得很完美。
public class FooBarMain {
public static void main(String[] args) {
DynamoDBMapper mapper = new DynamoDBMapper(
AmazonDynamoDBClientBuilder.standard().build(),
DynamoDBMapperConfig
.builder()
.withTableNameOverride(new DynamoDBMapperConfig.TableNameOverride("foobar"))
.build()
);
mapper.save(new FooBarRow("foobar1", new FooBar(123, 4)));
mapper.load(FooBarRow.class, "foobar1").getFooBar();
}
}
英文:
I've found an appropriate type to use for the source - AttributeValue
. Here's the converter:
public class FooBarConverter implements DynamoDBTypeConverter<AttributeValue, FooBar> {
@Override
public AttributeValue convert(FooBar object) {
return new AttributeValue()
.addMEntry("foo", new AttributeValue().withN(Integer.toString(object.getFoo())))
.addMEntry("bar", new AttributeValue().withN(Integer.toString(object.getBar())));
}
@Override
public FooBar unconvert(AttributeValue object) {
Map<String, AttributeValue> objectM = object.getM();
int foo = Integer.parseInt(objectM.get("foo").getN());
int bar = Integer.parseInt(objectM.get("bar").getN());
return new FooBar(foo, bar);
}
}
Also, a class to represent the whole row in Dynamo:
public class FooBarRow {
private String key;
private FooBar fooBar;
public FooBarRow(
String key,
FooBar fooBar
) {
this.key = key;
this.fooBar = fooBar;
}
public FooBarRow() {
}
@DynamoDBHashKey
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@DynamoDBTypeConverted(converter = FooBarConverter.class)
public FooBar getFooBar() {
return fooBar;
}
public void setFooBar(FooBar fooBar) {
this.fooBar = fooBar;
}
}
Now, saving and loading FooBarRow
instances using a DynamoDBMapper
works perfectly.
public class FooBarMain {
public static void main(String[] args) {
DynamoDBMapper mapper = new DynamoDBMapper(
AmazonDynamoDBClientBuilder.standard().build(),
DynamoDBMapperConfig
.builder()
.withTableNameOverride(new DynamoDBMapperConfig.TableNameOverride("foobar"))
.build()
);
mapper.save(new FooBarRow("foobar1", new FooBar(123, 4)));
mapper.load(FooBarRow.class, "foobar1").getFooBar();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论