来自MongoDB BSON的Jackson ObjectMapper

笛里谁知壮士心,沙头空照征人骨。这篇文章主要讲述来自MongoDB BSON的Jackson ObjectMapper相关的知识,希望能为你提供帮助。
【来自MongoDB BSON的Jackson ObjectMapper】我得到了一个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_STRINGXMLGregorianCalendar calendar = super.deserialize(jp, ctxt); jp.nextToken(); // Skip END_OBJECTreturn 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 = "{ " + ""date":{ " + ""$numberLong":"1551172199214" " + "}, " + ""name":"Rick" " + "}"; 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'}


    推荐阅读