[JAVA-698] bson can't serialize class java.math.BigInteger Created: 20/Nov/12  Updated: 19/Oct/16  Resolved: 21/Nov/12

Status: Closed
Project: Java Driver
Component/s: None
Affects Version/s: 2.9.1
Fix Version/s: None

Type: Bug Priority: Blocker - P1
Reporter: Gina Chen Assignee: Unassigned
Resolution: Done Votes: 0
Labels: bson
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Red Hat Enterprise Linux Client release 5.8 (Tikanga)
ARCH=x86_64
spring-data-mongodb: 1.1.1 RELEASE



 Description   

While doing some load test, I got this exception from mongodb.

2012-11-16 16:09:41.031 [WARN] org.springframework.jms.listener.DefaultMessageListenerContainer  - Execution of JMS message listener failed, and no ErrorHandler has been set.
java.lang.IllegalArgumentException: can't serialize class java.math.BigInteger
        at org.bson.BasicBSONEncoder.putNumber(BasicBSONEncoder.java:373)
        at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:218)
        at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:174)
        at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:120)
        at com.mongodb.DefaultDBEncoder.writeObject(DefaultDBEncoder.java:27)
        at com.mongodb.OutMessage.putObject(OutMessage.java:267)
        at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:240)
        at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:205)
        at com.mongodb.DBCollection.insert(DBCollection.java:57)
        at com.mongodb.DBCollection.insert(DBCollection.java:100)
        at com.dreamworks.pam.logging.dao.mongodb.LogEntryDAOImpl.createLogEntry(LogEntryDAOImpl.java:88)
        at com.dreamworks.pam.logging.services.impl.LogEntryServiceImpl.createLogEntry(LogEntryServiceImpl.java:85)
        at com.dreamworks.pam.logging.services.jms.LogEntryMessageListener.onMessage(LogEntryMessageListener.java:67)
        at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:562)
        at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:500)
        at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:468)
        at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:326)
        at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:264)
        at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1071)
        at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:965)
        at java.lang.Thread.run(Thread.java:619)

Our script generated the same data with different "_id", "id" and "created" and most of them were inserted into database fine. This exception only happened sporadically.



 Comments   
Comment by Jochen Kemnade [ 26/Jun/15 ]

Oh, right, now I see the problem. Of course, there is a problem if you use a BigInteger in a map-like structure. In my case, I have something like a POJO codec (based on org.apache.tapestry:beanmodel:5.4-beta-26) and I have type information. That's why I thought it would be easy. But I thought of JAVA-1812 too.

Comment by Jeffrey Yemin [ 26/Jun/15 ]

Hi Jochen,

You can write a BigIntegerCodec, which will allow big integers to be encoded as part of documents, e.g.

    collection.insertOne(new Document("bigInt", new BigInteger("12345")).append("str", "This is a regular string"));

The problem is how to turn that BSON string back into a BigInteger on the way out. Presumably not all of your BSON strings will be big integers, so you can't decode all BSON strings to BigInteger. So when you read that document back out, you'll get a Document that looks like this:

   new Document("bigInt", "12345").append("str", "This is a regular string"));

Where a BigIntegerCodec becomes more useful is when it's combine with a POJO Codec of some sort. If you have a class like:

public class MyEntity {
    private BigInteger bigInt;
    private String str;
 
   // ...
}

Now we have type information for each field, and can choose the appropriate Codec when decoding, based on the nominal type of each field.

We plan to expose a generic POJO Codec in a future release of the driver, but for now you would have to roll your own.

Comment by Jochen Kemnade [ 26/Jun/15 ]

I'm currently facing the same issue with the 3.0 (Cocec-based) API. If I am not mistaken, it shouldn't be a problem to provide a Codec that serializes to a BSON string.

Comment by Jeffrey Yemin [ 21/Nov/12 ]

Gina,

This is expected behavior. Serializing BigInteger is problematic because there is no way to round-trip it. Because they can be of arbitrary size, the driver can't encode them as numbers, so they would have to be encoded as strings. But then when the driver decodes them, it wouldn't know to turn them back into BigInteger. Because of problems like this, in general the driver only supports serialization of a fixed set of types that match what's specified in BSON.

Generated at Thu Feb 08 08:52:52 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.