I have a code that reads data in a specific format from MongoDB. I need to test it.
In order to do so, I create a JSON with the data I want to test:
{
"id": ObjectId("57552e32e4b0839ede67e0af"),
"serial" : 574000690,
"startDate" : ISODate("2016-08-22T23:01:56.000Z"),
"endDate" : ISODate("2016-10-22T22:01:56.000Z"),
"reason": ""
}
This is the object that supposed to be created:
public static class MyObject implements Serializable{
private String id;
private long serial;
private Date startDate;
private Date endDate;
private String reason;
}
I have a code that reads a JSON file and creates a Mongo document, and write to a DB:
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);
Once the data is written, there's a code that tries to read the data from MongoDB and populate it into a MyObject
instance:
public MyObject(Document doc) {
id = doc.getObjectId(DBConstants.ID).toString();
serial = doc.getLong(DBConstants.SERIAL);
startDate = doc.getDate("startDate");
reason = doc.getString("source");
}
Which fails on a error message:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
Because of the line serial = doc.getLong(DBConstants.SERIAL);
. It basically gets the number from my JSON as "Integer" thus unable to read it as long.
I've tried the following line, and it works:
Long.parseLong(doc.get(DBConstants.SERIAL).toString())
But is it the best solution here? Will .toString()
always gets me the string representation of a number? Is there a way to keep a number in JSON that would cause it to be read as Long
?
Update:
@glytching gave an excellent answer!
I also discovered another way, apparently if you wrap the numerical elemnt of JSON in NumberLong
it will be parsed as Long
when translated from Mongo document.
So using the old code, I was able to make it work by changing my JSON like so:
{
"id": ObjectId("57552e32e4b0839ede67e0af"),
"serial" : NumberLong(574000690),
"startDate" : ISODate("2016-08-22T23:01:56.000Z"),
"endDate" : ISODate("2016-10-22T22:01:56.000Z"),
"reason": ""
}
The Mongo Java driver has determined that the value of serial
can 'fit' in an INT32 so it treats it as such. When you invoke doc.getLong()
you are asking the driver to cast its Integer to a Long, hence the class cast exception. If, for example, the value of serial
was 2147483648
(i.e. the max integer value + 1) then the Mongo Java driver would deem that to be an INT64 and you could then safely invoke doc.getLong()
.
So, since (a) you have modelled this attribute as a Long
in your class model and (b) not every persisted value of this attribute requires storage as an INT64
... you have to be sensitive to its persisted type when converting it into a Long.
How? Well, as long as the serial
attribute is persisted as some sort of number (e.g. INT32
, INT64
) then this call ...
doc.get(DBConstants.SERIAL)
... will always return an object which is some subclass of java.lang.Number
and therefore casting to Number
and using longValue()
will work.
For example:
serial = ((Number) doc.get(DBConstants.SERIAL)).longValue()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With