需求
希望通过Jackson 把 json 转为 DBObject
use jackson, convert json string to DBObject
尝试
刚开始实现这个功能的时候,没有想到这里有坑,直接写的代码,如下
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
DBObject dbObject = new BasicDBObject("h", "a");
String json = objectMapper.writeValueAsString(dbObject);
System.out.println(json);
DBObject readValue = objectMapper.readValue(json, DBObject.class);
System.out.println(readValue);
}
输出为
{"h":"a"}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.mongodb.DBObject, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: {"h":"a"}; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:892)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:139)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3736)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2726)
at xxx.AsyncMessageHelper.main(AsyncMessageHelper.java:91)
可以看到 序列化
这个过程是没有问题的,正常输出 {"h":"a"}
但是 反序列化
出了问题,抛了异常
看异常信息,大概问题是因为 DBObject
是一个接口,所以 Jackson
在实例化的时候,不知道该用哪个实现类去实例化
网上搜了很多文章,最后找到了一种可行的方案(也许还有其它的方案)
code
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
DBObject dbObject = new BasicDBObject("h", "a");
String json = objectMapper.writeValueAsString(dbObject);
System.out.println(json);
SimpleModule module = new SimpleModule();
module.addDeserializer(DBObject.class, new DBObjectDeserializer(DBObject.class));
objectMapper.registerModule(module);
DBObject readValue = objectMapper.readValue(json, DBObject.class);
System.out.println(readValue);
}
public static class DBObjectDeserializer extends StdDeserializer<DBObject> {
protected DBObjectDeserializer(Class<?> vc) {
super(vc);
}
@Override
public DBObject deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
String string = p.readValueAsTree().toString();
return (DBObject) JSON.parse(string);
}
}
输出
{"h":"a"}
{ "h" : "a"}
原理
首先,写了个DBObjectDeserializer
,实现了标准反序列化接口
在具体的反序列化方法deserialize
中,使用了 MongoDB
官方的 JSON
工具类(这个类的方法可以正常反序列化DBObject
)
其次,向我们的 ObjectMapper
注册了一个 SimpleModule
这个 module
有一个反序列化实例,就是我们刚刚写的 DBObjectDeserializer
参考
https://www.baeldung.com/jackson-custom-serialization
https://stackoverflow.com/a/12261133
https://stackoverflow.com/questions/41001302/jackson-deserializer-for-one-custom-field