DynamoDB JsonMarshaller无法反序列化对象列表 [英] DynamoDB JsonMarshaller cannot Deserialize List of Object

查看:165
本文介绍了DynamoDB JsonMarshaller无法反序列化对象列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Java类,它是DynamoDB中表的数据模型。我想使用 DynamoDBMapper 保存加载项目来自迪纳摩。该类的一个成员是 List< MyObject> 。所以我使用 JsonMarshaller< List< MyObject>> 来序列化和反序列化该字段。

I have a Java class which is the data-model of a table in DynamoDB. I want to use the DynamoDBMapper to save and load items from Dynamo. One member of the class is a List<MyObject>. So I used the JsonMarshaller<List<MyObject>> to serialize and de-serialize this field.

该列表可以通过 JsonMarshaller 成功序列化。但是,当我尝试检索条目并读取列表时,它会抛出异常: java.lang.ClassCastException:java.util.LinkedHashMap无法强制转换为MyObject 。看起来 JsonMarshaller 将数据反序列化为 LinkedHashMap 而不是 MyObject 。我怎样摆脱这个问题?

The list can be successfully serialized by the JsonMarshaller. 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 JsonMarshaller de-serialize the data into the LinkedHashMap instead of MyObject. How can I get rid of this problem?

MCVE:

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

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

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

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







// MyObject.java
public class MyObject {
  private String name;
  private String property;

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

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

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







// ObjectListMarshaller.java
public class ObjectListMarshaller extends JsonMarshaller<List<MyObject>> {}







// Test.java
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);
    mapper.save(model); // success

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


推荐答案

部分这里的问题是整个DynamoDB Mapper SDK如何处理泛型。接口DynamoDBMarshaller< T extends Object> 有一个方法 T unmarshall(Class< T> clazz,String obj),其中要反序列化的类作为参数传递。问题是键入擦除,并且SDK无法轻松解决此问题。杰克逊在某些情况下更聪明( JsonMarshaller 使用杰克逊),这解释了为什么序列化方法正常工作。

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.

您需要为反序列化提供更好的实现。你可以这样做的一种方法是实现 DynamoDBMarshaller 接口,而不是扩展另一个(我的意见),这样你就可以更好地控制类型的序列化方式。

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.

这是一个基本上是 JsonMarshaller 的复制/粘贴的例子,在<$ c的反序列化中进行了一些小的调整$ c>列表给你一个想法:

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.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMarshaller;
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();

    @Override
    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");
        }
    }

    @Override
    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);
        }
    }
}

这篇关于DynamoDB JsonMarshaller无法反序列化对象列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆