我得到了一个JSON,我将其序列化为MongoDB BasicDBObject并将其插入到DB中:
String serialized = "";
try {
serialized = OBJECT_MAPPER.writeValueAsString(customEx.getOut().getBody());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
collection.update(upsertQuery, BasicDBObject.parse(serialized), true, false);
在从DB读取DBObject时,我想使用ObjectMappers的'readValue'将其转换为POJO,并使用给定的类:
public static <T> T fromDB(DBObject o, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(o.toString(), clazz);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
我要将它转换为的类是从xsd sheme生成的,还包含时间戳/长值,如下所示:
@XmlRootElement(name = "ItemType")
public class ItemType {
@XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar date;
[...]
但是,这适用于较旧的Java MongoDB版本。现在长值被序列化为BSON,如下所示:
"date": {
"$numberLong": "1551172199214"
}
当我尝试使用Jacksons ObjectMapper反序列化时,我得到了
无法从START_OBJECT标记中反序列化
javax.xml.datatype.XMLGregorianCalendar
的实例
这个的原因很清楚,因为long值在一个自己的BSON-Style对象中。
到目前为止,我已经尝试过像这样使用BsonDocument:
public static <T> T fromDB(DBObject o, Class<T> clazz) {
try {
BsonDocument parse = BsonDocument.parse(o.toString());
return OBJECT_MAPPER.readValue(parse.toJson(), clazz);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
但是仍然没有将BSON部分转换为JSON。
有没有办法使用Jacksons ObjectMapper将BSON反序列化为给定的类?或者只是将其转换为DBObject而不使用BSON部件?
看起来您需要配置ObjectMapper以不同方式反序列化XMLGregorianCalendar。
public class XMLGregorianCalendarDeserializer extends JsonDeserializer<XMLGregorianCalendar> {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public XMLGregorianCalendar deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
Map<String, String> bsonStringAsMap =
objectMapper.readValue(
jsonParser.readValueAsTree().toString(), new TypeReference<Map<String, String>>() {});
String timestampString = bsonStringAsMap.get("$numberLong");
if (timestampString != null && !timestampString.isEmpty()) {
long timestamp = Long.parseLong(timestampString);
Date date = new Date(timestamp);
GregorianCalendar gregorianCalendar = new GregorianCalendar();
gregorianCalendar.setTime(date);
return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
}
return null;
}
}
然后你可以用这个注释字段并反序列化:
@JsonDeserialize(using=XMLGregorianCalendarDeserializer.class)
@XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar date;
如果日历字段被包装,我们需要打开它。我们可以扩展已经实现的CoreXMLDeserializers.GregorianCalendarDeserializer
:
class XmlGregorianCalendarDeserializer extends CoreXMLDeserializers.GregorianCalendarDeserializer {
@Override
public XMLGregorianCalendar deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
jp.nextToken(); // Skip FIELD_NAME
jp.nextToken(); // Skip VALUE_STRING
XMLGregorianCalendar calendar = super.deserialize(jp, ctxt);
jp.nextToken(); // Skip END_OBJECT
return calendar;
}
}
如果总是包裹XMLGregorianCalendar
,我们可以使用SimpleModule
注册这个deserialiser。见下面的例子:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ext.CoreXMLDeserializers;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import javax.xml.datatype.XMLGregorianCalendar;
public class Test {
public static void main(String[] args) throws Exception {
SimpleModule wrappedCalendarModule = new SimpleModule();
wrappedCalendarModule.addDeserializer(XMLGregorianCalendar.class, new XmlGregorianCalendarDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(wrappedCalendarModule);
String json = "{\n"
+ " \"date\":{\n"
+ " \"$numberLong\":\"1551172199214\"\n"
+ " },\n"
+ " \"name\":\"Rick\"\n"
+ "}";
System.out.println(mapper.readValue(json, Wrapper.class));
}
}
class Wrapper {
private XMLGregorianCalendar date;
private String name;
// getters, setters, toString
}
上面的代码打印:
Wrapper{date=2019-02-26T09:09:59.214Z, name='Rick'}