is.magl is.magl - 1 year ago 147
Java Question

DynamoDB JsonMarshaller cannot Deserialize List of Object

I have a Java class which is the data-model of a table in DynamoDB. I want to use the

items from Dynamo. One member of the class is a
. So I used the
to serialize and de-serialize this field.

The list can be successfully serialized by the
. However, when I try to retrieve the entry back and read the list, it throws an exception:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyObject
. It looks like that the
de-serialize the data into the
instead of
. How can I get rid of this problem?


@DynamoDBTable(tableName = "...")
public class Model {
private String id;
private List<MyObject> objects;

public Model(String id, List<MyObject> objects) { = id;
this.objects = objects;

@DynamoDBHashKey(attributeName = "id")
public String getId() { return; }
public void setId(String id) { = id; }

@DynamoDBMarshalling(marshallerClass = ObjectListMarshaller.class)
public List<MyObject> getObjects() { return this.objects; }
public void setObjects(List<MyObject> objects) { this.objects = objects; }

public class MyObject {
private String name;
private String property;

public MyObject() { }
public MyObject(String name, String property) { = name; = property;

public String getName() { return; }
public void setName(String name) { = name; }

public String getProperty() { return; }
public void setProperty(String property) { = property; }

public class ObjectListMarshaller extends JsonMarshaller<List<MyObject>> {}

public class Test {
private static DynamoDBMapper mapper;

static {
AmazonDynamoDBClient client = new AmazonDynamoDBClient(new ProfileCredentialsProvider()
mapper = new DynamoDBMapper(client);

public static void main(String[] args) {
MyObject obj1 = new MyObject("name1", "property1");
MyObject obj2 = new MyObject("name2", "property2");
List<MyObject> objs = Arrays.asList(obj1, obj2);

Model model = new Model("id1", objs);; // success

Model retrieved = mapper.load(Model.class, "id1");
for (MyObject obj : retrieved.getObjects()) { // exception

Answer Source

Part of the problem here is how the whole DynamoDB Mapper SDK deals with generics. The interface DynamoDBMarshaller<T extends Object> has a method T unmarshall(Class<T> clazz, String obj), in which the class to deserialize to is passed as a parameter. The problem is that there is type erasure, and the SDK doesn't provide an easy to deal with this. Jackson is smarter in some cases (the JsonMarshaller uses Jackson), which explains why the serialize method works correctly.

You need to provide a better implementation for your deserialization. One way you could do this would be to implement the DynamoDBMarshaller interface rather than extending the other one (my opinion) so you have better control over how the type is serialized.

Here is an example that is essentially copy/paste of the JsonMarshaller, with minor tweaks in deserialization for the List to give you an idea:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.type.CollectionType;

import java.util.List;

import static com.amazonaws.util.Throwables.failure;

public class MyCustomMarshaller implements DynamoDBMarshaller<List<MyObject>> {

    private static final ObjectMapper mapper = new ObjectMapper();
    private static final ObjectWriter writer = mapper.writer();

    public String marshall(List<MyObject> obj) {

        try {
            return writer.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw failure(e,
                          "Unable to marshall the instance of " + obj.getClass()
                          + "into a string");

    public List<MyObject> unmarshall(Class<List<MyObject>> clazz, String json) {
        final CollectionType
            type =
            mapper.getTypeFactory().constructCollectionType(List.class, MyObject.class);
        try {
            return mapper.readValue(json, type);
        } catch (Exception e) {
            throw failure(e, "Unable to unmarshall the string " + json
                             + "into " + clazz);
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download