is.*_*agl 12 java jackson amazon-dynamodb
我有一个Java类,它是DynamoDB中表的数据模型.我想使用Dynamo中的DynamoDBMapperto save和loaditems.该班的一名成员是List<MyObject>.所以我用它JsonMarshaller<List<MyObject>>来序列化和反序列化这个字段.
该列表可以通过成功序列化JsonMarshaller.但是,当我尝试检索条目并读取列表时,它会抛出异常:java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyObject.看起来JsonMarshaller将数据反序列化为LinkedHashMap而不是MyObject.我该怎样摆脱这个问题?
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; }
}
Run Code Online (Sandbox Code Playgroud)
// 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; }
}
Run Code Online (Sandbox Code Playgroud)
// ObjectListMarshaller.java
public class ObjectListMarshaller extends JsonMarshaller<List<MyObject>> {}
Run Code Online (Sandbox Code Playgroud)
// 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
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ale*_*ris 11
在较新的版本中,只需使用:
@DynamoDBAttribute(attributeName = "things")
public List<Thing> getThings() {
return things;
}
public void setThings(final List<Thing> things) {
this.things = things;
}
Run Code Online (Sandbox Code Playgroud)
鉴于Thing的注释:
@DynamoDBDocument
public class Thing {
}
Run Code Online (Sandbox Code Playgroud)
这里的部分问题是整个DynamoDB Mapper SDK如何处理泛型.该interface DynamoDBMarshaller<T extends Object>有一个方法T unmarshall(Class<T> clazz, String obj),其中,所述类反序列化到作为参数传递.问题是存在类型擦除,并且SDK不提供易于处理的问题.杰克逊在某些情况下更聪明(JsonMarshaller使用杰克逊),这解释了为什么serialize方法正常工作.
您需要为反序列化提供更好的实现.你可以做到这一点的一种方法是实现DynamoDBMarshaller接口而不是扩展另一个(我的意见),这样你就可以更好地控制类型的序列化方式.
这是一个基本上是复制/粘贴的示例,JsonMarshaller在反序列化中进行了小调整,List以便为您提供一个想法:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
DynamoDBMarshaller 现在已弃用,但我遇到了与 DynamoDBTypeConvertedJson 完全相同的问题。如果您想将集合作为 JSON 存储在 DynamoDBMapper 类中,请使用 DynamoDBTypeConverted 并编写自定义转换器类(不要使用 DynamoDBTypeConvertedJson,它不会在未转换时返回您的集合)。
这是使用 DynamoDBTypeConverted 的解决方案
// 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; }
@DynamoDBTypeConverted(converter = MyObjectConverter.class)
public List<MyObject> getObjects() { return this.objects; }
public void setObjects(List<MyObject> objects) { this.objects = objects; }
}
Run Code Online (Sandbox Code Playgroud)
——
public class MyObjectConverter implements DynamoDBTypeConverter<String, List<MyObject>> {
@Override
public String convert(List<Object> objects) {
//Jackson object mapper
ObjectMapper objectMapper = new ObjectMapper();
try {
String objectsString = objectMapper.writeValueAsString(objects);
return objectsString;
} catch (JsonProcessingException e) {
//do something
}
return null;
}
@Override
public List<Object> unconvert(String objectssString) {
ObjectMapper objectMapper = new ObjectMapper();
try {
List<Object> objects = objectMapper.readValue(objectsString, new TypeReference<List<Object>>(){});
return objects;
} catch (JsonParseException e) {
//do something
} catch (JsonMappingException e) {
//do something
} catch (IOException e) {
//do something
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11646 次 |
| 最近记录: |