来自MongoDB BSON的Jackson ObjectMapper

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了来自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_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 = "{
"
            + "   "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'}

以上是关于来自MongoDB BSON的Jackson ObjectMapper的主要内容,如果未能解决你的问题,请参考以下文章

NodeJS 中 BSON 对象的 console.log

MongoDB:BSON 到 JSON

c++ bson扩展加载失败,使用mongodb访问mongodb时使用纯js版本

mongodb集群用户名密码怎么设置

运行节点脚本时出错,找不到模块 'mongodb/node_modules/bson'

如何使用 Python 将 MongoDB 的 bsondump 转换为 JSON?