Java 将MongoDB 3中的文档对象转换为POJO

Java 将MongoDB 3中的文档对象转换为POJO,java,json,mongodb,mongodb-java,Java,Json,Mongodb,Mongodb Java,我正在将带有java.util.Date字段的对象保存到MongoDB 3.2实例中 ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(myObject); collection.insertOne(Document.parse(json)); 该字符串包含: "captured": 1454549266735 "captured": { "$numberLong": "

我正在将带有java.util.Date字段的对象保存到MongoDB 3.2实例中

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(myObject);
collection.insertOne(Document.parse(json));
该字符串包含:

"captured": 1454549266735
"captured": {
    "$numberLong": "1454550216318"
}
然后我从MongoDB实例中读到:

    final Document document = collection.find(eq("key", value)).first();
    final String json = document.toJson();
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    xx = mapper.readValue(json, MyClass.class);
反序列化失败:

java.lang.RuntimeException:com.fasterxml.jackson.databind.JsonMappingException: 无法反序列化java.util.Date的实例,该实例不在START\u对象标记内

我看到“document.toJson()”创建的json字符串包含:

"captured": 1454549266735
"captured": {
    "$numberLong": "1454550216318"
}
而不是最初的(“捕获”:1454549266735) MongoDB文档称他们开始使用“MongoDB扩展Json”。我尝试了Jackson 1和Jackson 2来解析它-没有运气

将MongoDB 3提供的文档对象转换为Java POJO的最简单方法是什么?也许我可以跳过JSON()步骤

我试过mongojack,但它不支持MongoDB3


查看了MongoDB文档页面上列出的其他两个POJO映射程序-它们都需要将自定义注释放入Java类。

这看起来像Mongo Java驱动程序错误,Document.toJson提供了非标准JSON,即使使用了JsonMode.STRICT。这个问题在下面的bug中有描述,我鼓励您对此进行投票


一种解决方法是使用com.mongodb.util.JSON.serialize(document)。

看起来您在“myObject”中使用的是日期对象。在这种情况下,您应该使用一个
DateSerializer
,它实现了
JsonSerializer、jsonderializer
,然后将其注册到
GsonBuilder
。示例代码如下:

public class My_DateSerializer implements JsonSerializer<LocalDate>,
                                                          JsonDeserializer<LocalDate> {

@Override
public LocalDate deserialize(JsonElement json, Type typeOfT,
                        JsonDeserializationContext context) throws JsonParseException {
    final String dateAsString = json.getAsString();
    final DateTimeFormatter dtf = DateTimeFormat.forPattern(DATE_FORMAT);
    if (dateAsString.length() == 0)
    {
        return null;
    }
    else
    {
        return dtf.parseLocalDate(dateAsString);
    }
}

@Override
public JsonElement serialize(LocalDate src, Type typeOfSrc,
                                                     JsonSerializationContext context) {
    String retVal;
    final DateTimeFormatter dtf = DateTimeFormat.forPattern(DATE_FORMAT);
    if (src == null)
    {
        retVal = "";
    }
    else
    {
        retVal = dtf.print(src);
    }
    return new JsonPrimitive(retVal);
}
}

您应该定义并使用自定义JsonWriterSettings来微调JSON生成:

 JsonWriterSettings settings = JsonWriterSettings.builder()
         .int64Converter((value, writer) -> writer.writeNumber(value.toString()))
         .build();

 String json = new Document("a", 12).append("b", 14L).toJson(settings);
将产生:

 { "a" : 12, "b" : 14 }
如果不使用自定义设置,则文档将生成扩展json:

 { "a" : 12, "b" : { "$numberLong" : "14" } }

我用mongo文档保存一个标记,该标记指定存储的对象的原始类型。然后,我使用Gson用该类型的名称解析它。首先,创建存储的文档

private static Gson gson = new Gson();

public static Document ConvertToDocument(Object rd) {
    if (rd instanceof Document)
        return (Document)rd;
    String json = gson.toJson(rd);
    Document doc = Document.parse(json); 
    doc.append(TYPE_FIELD, rd.getClass().getName());
    return doc;
}
然后将文档读回Java

public static Object ConvertFromDocument(Document doc) throws CAAException {
    String clazzName = doc.getString(TYPE_FIELD);
    if (clazzName == null)
        throw new RuntimeException("Document was not stored in the DB or got stored without becing created by itemToStoredDocument()");
    Class<?> clazz;
    try {
        clazz = (Class<?>) Class.forName(clazzName);
    } catch (ClassNotFoundException e) {
        throw new CAAException("Could not load class " + clazzName, e);
    }

    json = com.mongodb.util.JSON.serialize(doc);
    return gson.fromJson(json, clazz);
}
公共静态对象ConvertFromDocument(文档文档)引发异常{
String clazzName=doc.getString(TYPE_字段);
if(clazzName==null)
抛出新的RuntimeException(“文档未存储在DB中,或未通过itemToStoredDocument()创建而存储”);
课堂讨论;
试一试{
clazz=(Class)Class.forName(clazzName);
}catch(classnotfounde异常){
抛出新异常(“无法加载类”+clazzName,e);
}

json=com.mongodb.util.json.serialize(doc); 返回gson.fromJson(json,clazz); }

感谢Aleksey指出JSON.serialize()。

com.mongodb.util.JSON.serialize(文档)在新版本中被弃用编辑:简单明了的谢谢。完美的答案!谢谢这种方法的一个潜在问题是,较大的long值可能会失去精度。一些JSON实现只使用双精度。它们有52位尾数,比长尾数少12位。幸运的是,以毫秒为单位的划时代时间目前只需要31位,所以我们在很多情况下(143000年)都可以避免这种情况,但要小心!现在,JsonMode.RELAXED更简单了:您是如何解决这个问题的-我得到了错误类型不匹配所需的转换器[Long]Actual[(Any,Any),Nothing]。无法解析符号值。