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 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 (as described here) 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) {
...
}
}
DynamoDBMappingException: not supported; requires @DynamoDBTyped or @DynamoDBTypeConvertedconvert() method is always emptyDynamoDBMappingException: could not resolve type of class FooBarConverterIf we regard both the Java class and the storage format as being unmodifiable, what solution is there?
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With