MongoDB:尝试从 JSON 读取 Long 会导致 java.lang.Integer 无法转换为 java.lang.Long

MongoDB: trying to read Long from JSON causes java.lang.Integer cannot be cast to java.lang.Long

我有一个代码可以从 MongoDB 读取特定格式的数据。我需要测试一下。

为此,我用我要测试的数据创建了一个 JSON:

{
  "id": ObjectId("57552e32e4b0839ede67e0af"),
  "serial" : 574000690,
  "startDate" : ISODate("2016-08-22T23:01:56.000Z"),
  "endDate" : ISODate("2016-10-22T22:01:56.000Z"),
  "reason": ""
}

这是应该创建的对象:

public static class MyObject implements Serializable{
    private String id;
    private long serial;
    private Date startDate;
    private Date endDate;
    private String reason;
}

我有一个代码可以读取 JSON 文件并创建 Mongo 文档,然后写入数据库:

List<Document> docs = dirAsDbObjects(dir + File.separator + 
subDir.getName()).collect(Collectors.toList());

docs.forEach(docManipulator);
docs.forEach(doc -> doc.putIfAbsent("_id", new ObjectId()));

ret.addAll(docs);

MongoDatabase db = mongoClient.getDatabase(dbName);
MongoCollection<Document> coll = db.getCollection(subDir.getName());

List<InsertOneModel<Document>> inserts = docs.stream().map(InsertOneModel::new).collect(Collectors.toList());
coll.bulkWrite(inserts);

写入数据后,有一段代码会尝试从 MongoDB 读取数据并将其填充到 MyObject 实例中:

    public MyObject(Document doc) {
        id = doc.getObjectId(DBConstants.ID).toString();
        serial = doc.getLong(DBConstants.SERIAL);
        startDate = doc.getDate("startDate");
        reason = doc.getString("source");
    }

错误消息失败:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

因为第 serial = doc.getLong(DBConstants.SERIAL); 行。它基本上从我的 JSON 中获取数字 "Integer" 因此无法长时间读取它。

我试过以下行,它有效:

Long.parseLong(doc.get(DBConstants.SERIAL).toString())

但这是最​​好的解决方案吗? .toString() 总能得到数字的字符串表示形式吗?有没有办法在 JSON 中保留一个数字,使其被读取为 Long

更新:

@glytching 给出了很好的答案!

我还发现了另一种方法,显然如果你将 JSON 的数字元素包装在 NumberLong 中,当从 Mongo 文档翻译时,它将被解析为 Long

所以使用旧代码,我可以通过像这样更改 JSON 来使其工作:

{
  "id": ObjectId("57552e32e4b0839ede67e0af"),
  "serial" : NumberLong(574000690),
  "startDate" : ISODate("2016-08-22T23:01:56.000Z"),
  "endDate" : ISODate("2016-10-22T22:01:56.000Z"),
  "reason": ""
}

Mongo Java 驱动程序已确定 serial 的值可以 'fit' 为 INT32,因此它会这样对待它。当您调用 doc.getLong() 时,您要求驱动程序将其 Integer 转换为 Long,因此出现 class 转换异常。例如,如果 serial 的值为 2147483648(即最大整数值 + 1),那么 Mongo Java 驱动程序会认为它是一个 INT64 而你然后可以安全地调用 doc.getLong().

因此,因为 (a) 您已在 class 模型中将此属性建模为 Long 并且 (b) 并非此属性的每个持久值都需要存储为 INT64 ...在将其转换为 Long 时,您必须对其持久化类型敏感。

怎么样?好吧,只要 serial 属性作为某种数字(例如 INT32INT64)持久化,那么这个调用 ...

doc.get(DBConstants.SERIAL)

... 将始终 return 一个对象,该对象是 java.lang.Number 的某个子 class,因此转换为 Number 并使用 longValue() 将起作用.

例如:

serial = ((Number) doc.get(DBConstants.SERIAL)).longValue()