问题描述
我有一个 Java 类,它是 DynamoDB 中表的数据模型.我想使用 DynamoDBMapper
来 save
和 load
来自 Dynamo 的项目.该类的一个成员是 List
.所以我使用 JsonMarshaller
来序列化和反序列化这个字段.
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 cannot be cast to 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 如何处理泛型.interface DynamoDBMarshaller
有一个方法T unmarshall(Class clazz, String obj)
,其中将要反序列化的类作为参数传递.问题是存在类型擦除,SDK 没有提供易于处理的方法.Jackson 在某些情况下更聪明(JsonMarshaller
使用 Jackson),这就解释了为什么 serialize
方法可以正常工作.
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
的示例,对 List
的反序列化进行了细微的调整,以给您一个想法:
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 无法反序列化对象列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!