aws-sdk-java
aws-sdk-java copied to clipboard
Support for inheritance in DynamoDbMapper
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 Animal
class to the db and retrieve them as well. Ready to supply meta information similar to @JsonTypeInfo
and the likes.
Looks like this is not supported right now.
http://stackoverflow.com/questions/39221525/dynamodbmapper-support-for-inheritance
I was able to inherit from an abstract class using DynamoDBMapper by notating both the abstract class and the subclass with the @DynamoDBTable annotation.
It would work if the operations are performed on Dog/Cat (concrete instances) vs Animal (abstract instance)
Support for polymorphism would mean operating on base class (put and get 'Animal' and the type information is handled automatically)
@sowdri Yeah, I only extended my abstract class as a means to add common attributes. I only attempted performing operations on my concrete classes. I did not attempt any polymorphism.
@sowdri - it's certain possible to save polymorphic types - in this case the mapper can get to the concrete implementation and uses the annotations on that to do the persistence to dynamo (ie: Cat
will pick up additional properties of the Cat
object and add those fields)
class Cat extends Animal {
@DynamoDBAttribute(attributeName = "furLength")
public String getFurLength() { return furLength; }
public void setFurLength() { this.furLength = furLength; }
}
Animal cat = new Cat();
cat.setFurLength("long");
mapper.save(cat);
In this case, the furLength
property will get persisted.
However at present the way the load mechanism works one must specify the concrete type you're trying to load.
I like the idea of having an additional annotation on the base-class that specifies sub-types to convert to - this would mean we'd need to store additional fields against the object in dynamo - but it could be a cool feature.
This is something we can look to add in a future release.
@kiiadi Thanks for your reply.
For anyone who is looking for a solution for this problem. You could simple use Jackson for serialization/deserialization and use the low-level Item API (using the Item.fromJson() and Item.toJson()) for putting and getting polymorphic types in and out of Dynamo.
For anyone looking for a quick solution until this feature is implemented, I've posted the code of a base class just for reference.
public abstract class DynamoServiceImpl<T extends Base<String>> implements DynamoService<T> {
@Autowired
@AwsConfig.DynamoMapper
private ObjectMapper objectMapper;
@Autowired
private DynamoDB db;
abstract String getTable();
abstract Class<?> getType();
@Override
public T get(String id) {
Table table = db.getTable(getTable());
Item item = table.getItem("id", id);
String s = item.toJSON();
Object obj;
try {
obj = objectMapper.readValue(s, getType());
} catch (IOException e) {
e.printStackTrace();
return null;
}
return (T)obj;
}
@Override
public T put(T obj) {
/**
* Check if item has id, else populate it
*/
if (obj.getId() == null) {
obj.setId(uuid());
}
Table table = db.getTable(getTable());
String jsonStr;
try {
jsonStr = objectMapper.writeValueAsString(obj);
System.out.println(jsonStr);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException("Cannot write item");
}
Item item = Item.fromJSON(jsonStr);
table.putItem(item);
return obj;
}
}```
+1 Looking for the exact same feature in DynamoDBMapper.
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
Initial proposal for supporting polymorphism in DynamoDB mapper - pr #1229
+1
Any updates about when it will be implemented? It's very useful feature.
As @fpoolev had pointed out above (in Sep 2016), simply adding (dummy, unused) annotations to super-classes seems to work for cases where dynamic typing isn't required (e.g., for a dummy table named X
):
@DynamoDBTable(tableName = "X")
public abstract class X ...
Table "X" needn't exist, and such dummy annotations permit attributes of classes like X
to appear in documents for subclasses of X
.
@dratc Unfortunately as I understand it, this does not fully fix this issue as it won't allow for dynamic types and linking using the @DynamoDBDocument
annotations to compose varying types. It is probably still possible to achieve similar behaviour by using the low level SDKs for dynamo but having native support in the mapper would make our lives much easier 😄
We already use the solution you mentioned above, which is limited, and would still very much like the flexibility this issue addresses!
@ben-bourdin451 I'm not sure I fully understand your use-case - what do you mean by dynamic types?
@AliakseiMat @dratc I've put out a PR #1229 which I'm looking to get some feedback on.
Hello,
moving from aws-sdk.version : 1.10.49 to 1.11.246
my previous polymorphism implementation is not working anymore... :(
(previously working with lombok @Getter (onMethod = @__({@DynamoDBAttribute, @ApiModelProperty("...")})) moved to simple @DynamoDBAttribute with real getters & setters do not change a thing...)
any info related to this issue ? seems like sdk is not ascending compatible... what a deception :(
sincerely
i42
Any updates on this please?
This seems to be very important feature. Any progress with it?
I can agree with @SergiiSopin without this you need to do some "hacky" things to persist such objects. Could you consider implementing support for this?
It's unlikely that this will be prioritized for V1 of the Java SDK, because of the associated performance and operational risks. We're primarily focused on V2 of the Java SDK, so we will be implementing this there at some point, but I don't have an ETA.
I'll check in with the team whether we want to close this issue to prevent confusion.
Unfortunately the attached pull request doesn't have enough tests (either functional or performance) for the Java SDK team to merge as-is, and we haven't prioritized doing that testing, since a lot of people are very vocal about wanting us to focus on V2 of the SDK.
I've created a feature request for adding this feature to the V2 DynamoDB enhanced client: https://github.com/aws/aws-sdk-java-v2/issues/1870. We're currently leaning towards just doing this with the enhanced client in V2, since that's much better tested and understood.