DynamoDBTypeConverter 用于没有注解的DynamoDB文档字段

huangapple go评论83阅读模式
英文:

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:
	
`{ &quot;foo&quot; : { &quot;N&quot; : &quot;45&quot; }, &quot;bar&quot; : { &quot;N&quot; : &quot;12&quot; }}`

I&#39;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&#39;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&#39;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&#39;d like to use a [DynamoDBTypeConverter][2] (as described [here][3]) to write my own conversion, but I cannot find a suitable &#39;source&#39; 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&#39;t error but the string supplied to the `convert()` method is always empty
 - Object, which would seem to be a catch-all, isn&#39;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&lt;AttributeValue, FooBar&gt; {
  @Override
  public AttributeValue convert(FooBar object) {
    return new AttributeValue()
        .addMEntry(&quot;foo&quot;, new AttributeValue().withN(Integer.toString(object.getFoo())))
        .addMEntry(&quot;bar&quot;, new AttributeValue().withN(Integer.toString(object.getBar())));
  }

  @Override
  public FooBar unconvert(AttributeValue object) {
    Map&lt;String, AttributeValue&gt; objectM = object.getM();
    int foo = Integer.parseInt(objectM.get(&quot;foo&quot;).getN());
    int bar = Integer.parseInt(objectM.get(&quot;bar&quot;).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(&quot;foobar&quot;))
            .build()
    );

    mapper.save(new FooBarRow(&quot;foobar1&quot;, new FooBar(123, 4)));

    mapper.load(FooBarRow.class, &quot;foobar1&quot;).getFooBar();
  }
}

huangapple
  • 本文由 发表于 2020年10月19日 17:39:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/64424766.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定