Reputation: 41
I'm using dynamodb and the java class I'm storing has the following structure:
@DynamoDBTable(tableName="Animals")
class abstract Animal {
@DynamoDBHashKey(attributeName = "Id")
@DynamoDBAutoGeneratedKey
String id;
}
class Dog extends Animal {
// ... dog props
}
class Cat extends Animal {
// ... cat props
}
I would like to save instances of Dog/Cat to the db and retrieve them as well. Ready to supply meta information similar to @JsonTypeInfo
and the likes.
Let me know if this is supported. Or any workarounds for storing polymorphic types from Java in DynamoDb.
Thanks in advance,
Upvotes: 3
Views: 8603
Reputation: 39196
You can use the inheritance concept as you described above. The DynamoDBMapper save() method should be able to save Dog and Cat successfully.
However, when you retrieve the data using DynamoDBMapper load(), you need to provide correct class name.
When you execute the load () method with Animal.class, the API will throw "Failed to instantiate class" exception if Animal class is defined as abstract.
Example load() method to get Animal data:-
dynamoDBMapper.load(Animal.class,id,
new DynamoDBMapperConfig(DynamoDBMapperConfig.ConsistentReads.CONSISTENT));
Exception:-
Caused by: com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: Failed to instantiate class
Workaround 1:-
You can get the Animal data using QuerySpec. The disadvantage of this is that you need to get the value for each key individually as you are not getting the data using DynamoDBMapper class.
DynamoDB dynamoDB = new DynamoDB(dynamoDBClient);
Table table = dynamoDB.getTable("Animals");
ItemCollection<QueryOutcome> items = null;
QuerySpec querySpec = new QuerySpec();
querySpec.withKeyConditionExpression("Id = :val1").withValueMap(new ValueMap().withString(":val1", animalId));
items = table.query(querySpec);
Iterator<Item> iterator = items.iterator();
while (iterator.hasNext()) {
Item itemData = iterator.next();
System.out.println("Json data ====================>" + itemData.toJSONPretty());
System.out.println("Dogname : " + itemData.getString("dogname"));
System.out.println("Catname : " + itemData.getString("catname"));
}
Workaround 2:-
You can declare the Animal class as normal class (i.e. without abstract). In this approach, you can get the data using DynamoDBMapper. However, you will not see the child class attributes.
If you know that you are going to get CAT or DOG object, you can specify that as class name accordingly during load().
When you get DOG:-
Dog dog = dynamoDBMapper.load(Dog.class, id,
new DynamoDBMapperConfig(DynamoDBMapperConfig.ConsistentReads.CONSISTENT));
When you get CAT:-
Cat cat = dynamoDBMapper.load(Cat.class, id,
new DynamoDBMapperConfig(DynamoDBMapperConfig.ConsistentReads.CONSISTENT));
Upvotes: 4
Reputation: 579
You could use @DynamoDBDocument to serialize objects. The documentation has a nice example to demonstrate the usage of this annotation as well.
Upvotes: -1