0
votes

I have a toy DynamoDB table with a hash key, and in it I want to store some simple items in DynamoDB document format.

Here's the class to represent the document:

@DynamoDBDocument
public class Simple {
  private String key;
  private String value;

  public Simple() {
  }

  public Simple(
      String key,
      String value
  ) {
    this.key = key;
    this.value = value;
  }

  @DynamoDBAttribute
  public String getKey() {
    return key;
  }

  public void setKey(String key) {
    this.key = key;
  }

  @DynamoDBAttribute
  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }
}

and here's a class to represent the entry in the table:

@DynamoDBDocument
public class SimpleRow {
    private String hash;
  private Simple entry;

  public SimpleRow() {
  }

  public SimpleRow(
      String hash,
      Simple entry
  ) {
    this.hash = hash;
    this.entry = entry;
  }

  @DynamoDBHashKey
  public String getHash() {
    return hash;
  }

  public void setHash(String hash) {
    this.hash = hash;
  }

  @DynamoDBAttribute
  public Simple getEntry() {
    return entry;
  }

  public void setEntry(Simple entry) {
    this.entry = entry;
  }
}

With this setup, I can save entries to and laod entries from the table without a problem, using a DynamoDBMapper:

DynamoDBMapper mapper = new DynamoDBMapper(
        AmazonDynamoDBClientBuilder.standard().build(),
        DynamoDBMapperConfig
            .builder()
            .withTableNameOverride(new DynamoDBMapperConfig.TableNameOverride("simple"))
            .build()
    );
    mapper.save(new SimpleRow("the-hash", new Simple("foo", "bar")));
    System.out.println(mapper.load(SimpleRow.class, "the-hash"));

which results in an entry looking like this:

{
  "entry": {
    "M": {
      "key": {
        "S": "foo"
      },
      "value": {
        "S": "bar"
      }
    }
  },
  "hash": {
    "S": "the-key"
  }
}

However, I dislike the pollution of the Simple class with setters and zero-argument constructor - it should be an immutable data class. Therefore, I'd like to use a DynamoDBTypeConverter to construct the Simple objects.

The problem is I can't seem to write a converter that works, as I can't find a suitable source type:

  • 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 SimpleConverter

Is it possible to write a DynamoDBTypeConverter for this type? If so, what type should I use? I've trawled the internet for exampels of this but nothing seems forthcoming.

1
What is your expected output?prem30488
An instance of the Simple class. If the attribute in the table is { "key" : { "S" : "foo" }, "value" : { "S" : "bar" } }, I'd want to return new Simple("foo", "bar")Paul Davies
I did not get you. I think there is a need to change structure of your POJO.prem30488
Remove private String key; in SimpleRow.java and its getter setters and check. I am not sure what is expected.prem30488
Sorry, I've realised I've used the words key and value twice. Let me modify the question to clarify.Paul Davies

1 Answers

0
votes

You need to change Simple to Simple[] in SimleRow.java

import java.util.Arrays;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDocument;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;

@DynamoDBDocument
public class SimpleRow {
  private String hash;
  private Simple[] entry;

  public SimpleRow() {
  }

  public SimpleRow(
      String hash,
      Simple[] entry
  ) {
    this.hash = hash;
    this.entry = entry;
  }

  @DynamoDBHashKey
  public String getHash() {
    return hash;
  }

  public void setHash(String hash) {
    this.hash = hash;
  }

  @DynamoDBAttribute
  public Simple[] getEntry() {
    return entry;
  }

  public void setEntry(Simple[] entry) {
    this.entry = entry;
  }

@Override
public String toString() {
    StringBuilder builder = new StringBuilder();
    builder.append("SimpleRow [hash=");
    builder.append(hash);
    builder.append(", entry=");
    builder.append(Arrays.toString(entry));
    builder.append("]");
    return builder.toString();
}
}

And call it in main class as new SimpleRow("the-hash", new Simple[] {new Simple("foo", "bar")})

 mapper.save(new SimpleRow("the-hash", new Simple[] {new Simple("foo", "bar")}));