1

We use MongoDB and we get this error:

class java.lang.Double cannot be cast to class java.lang.Long (java.lang.Double and java.lang.Long are in module java.base of loader ‘bootstrap’)

The stacktrace:

{
  "file": "Document.java",
  "method": "getLong",
  "line": 266,
  "exact": false,
  "location": "bson-3.11.0.jar",
  "class": "org.bson.Document",
  "version": "?"
},
{
  "file": "Util.kt",
  "method": "determineLastChanged",
  "line": 11,
  "exact": false,
  "location": "foobar-backend-persist-2020.47.5.jar",
  "class": "com.foobar.persist.trash.UtilKt",
  "version": "?"
},

Our code:

// com.foobar.persist.trash.UtilKt

import org.bson.Document

internal fun determineLastChanged(trashDoc: Document): Long {
  return trashDoc.getLong("_touched")
    ?: trashDoc.getLong("_created")
    ?: trashDoc.getDocument("_trash")?.getLong("deletedAt")
    ?: throw InternalTrashException("trash item without timestamp")
}

I know Java, but I am new to MongoDB. I worked with SQL in the past.

This error is rare, but if it happens, it is reproducible.

What could be the reason?

1

2 Answers 2

3
+150

The problem probably is that any of the indicated fields is actually stored as Double instead of Long.

As you can see in the source code of the Document class, in the getLong method you can find the following:

return (Long) get(key);

This cast is the one that is causing the error reported by the Mongo driver.

Is it possible that some of your timestamps are created with Javascript and NodeJS, perhaps with the Mongo shell? If that is the case, depending on how you create the timestamp, the value of your field could be inserted as double due to the way numbers are represented in Javascript.

The mongo shell documentation indicates:

The mongo shell treats all numbers as floating-point values by default.

And:

The mongo shell treats all numbers as 64-bit floating-point double values by default.

The issue has been documented here in SO in this question. It is quite dated, but it could be a possible explanation of your problem.

This article, although also quite dated and not directly related with your problem, provides some additional background.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. I created a follow-up question: How to force the datatype in MongoDB
You are welcome, and thank you @guetti. I will try to help you with the new question as well. Again, thank you very much.
1

If the database contains a mix of integer and floating point types for a particular field, and you want to treat them all as long in your Java code, you could use the java.lang.Number class, like so:

  trashDoc.get("_created", Number.class).longValue()

Since Double, Integer, and Long all extend Number, this code will work to extract a long value from any numeric field. Just keep in mind that if the value is a Double, it will discard the fractional part of the Double, i.e.

    Document d = new Document()
            .append("_created", 4.2);
    System.out.println(d.get("_created", Number.class).longValue());

will print 4

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.