aws-sdk-java icon indicating copy to clipboard operation
aws-sdk-java copied to clipboard

Support for inheritance in DynamoDbMapper

Open sowdri opened this issue 8 years ago • 30 comments

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

sowdri avatar Aug 31 '16 02:08 sowdri

I was able to inherit from an abstract class using DynamoDBMapper by notating both the abstract class and the subclass with the @DynamoDBTable annotation.

fpoolev avatar Sep 01 '16 00:09 fpoolev

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 avatar Sep 06 '16 06:09 sowdri

@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.

fpoolev avatar Sep 06 '16 20:09 fpoolev

@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 avatar Sep 19 '16 16:09 kiiadi

@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;
    }
}```

sowdri avatar Sep 27 '16 04:09 sowdri

+1 Looking for the exact same feature in DynamoDBMapper.

ranjitparva avatar Oct 21 '16 20:10 ranjitparva

+1

arnoldtempfli avatar Nov 09 '16 15:11 arnoldtempfli

+1

matelang avatar Nov 09 '16 15:11 matelang

+1

destebanm avatar Jan 19 '17 15:01 destebanm

+1

oscartoledo avatar Jan 30 '17 15:01 oscartoledo

+1

safrain avatar Mar 24 '17 08:03 safrain

+1

bita-c avatar Apr 26 '17 01:04 bita-c

+1

david-ratcliffe avatar May 02 '17 04:05 david-ratcliffe

+1

chrislockSB avatar May 02 '17 21:05 chrislockSB

+1

gleb-urvanov avatar May 10 '17 13:05 gleb-urvanov

+1

brunodelphim avatar Jun 26 '17 11:06 brunodelphim

+1

andrerip avatar Jun 26 '17 11:06 andrerip

+1

zachpepsin avatar Jun 30 '17 17:06 zachpepsin

Initial proposal for supporting polymorphism in DynamoDB mapper - pr #1229

kiiadi avatar Jul 12 '17 22:07 kiiadi

+1

ghost avatar Aug 17 '17 18:08 ghost

Any updates about when it will be implemented? It's very useful feature.

AliakseiMat avatar Aug 24 '17 05:08 AliakseiMat

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.

david-ratcliffe avatar Aug 24 '17 05:08 david-ratcliffe

@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 avatar Aug 25 '17 09:08 ben-bourdin451

@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.

kiiadi avatar Aug 25 '17 22:08 kiiadi

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

dimPhotobox avatar Dec 12 '17 17:12 dimPhotobox

Any updates on this please?

mdamak avatar Feb 28 '20 11:02 mdamak

This seems to be very important feature. Any progress with it?

SergiiSopin avatar May 12 '20 18:05 SergiiSopin

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?

bercik avatar May 15 '20 14:05 bercik

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.

millems avatar May 15 '20 17:05 millems

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.

millems avatar Jun 02 '20 17:06 millems