Announcement Announcement Module
Collapse
No announcement yet.
Mongodb/BSON Fails to Serialize when BigInteger used as an ID Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mongodb/BSON Fails to Serialize when BigInteger used as an ID

    I instantiated a repository using BigInteger as the ID class:

    public interface PersonRepository extends PagingAndSortingRepository<Person, BigInteger>

    When I run the test (source and maven pom attached) which attempts to save a Person object to my mongodb, I get the following error:

    java.lang.IllegalArgumentException: can't serialize class java.math.BigInteger
    at org.bson.BSONEncoder.putNumber(BSONEncoder.java:31 7)
    at org.bson.BSONEncoder._putObjectField(BSONEncoder.j ava:168)
    at org.bson.BSONEncoder.putObject(BSONEncoder.java:10 5)
    at org.bson.BSONEncoder.putObject(BSONEncoder.java:70 )

    When I look at BSONEncoder.putNumber() it only supports Integer. Is BigInteger fully supported as an alternative to String?

    I am using:
    spring-data-mongodb 1.0.0.M3
    spring-data-commons-core 1.1.0.M1

  • #2
    I believe this is the same issue you are experiencing: https://jira.springsource.org/browse/DATADOC-171

    Comment


    • #3
      Thanks for that - I had searched but for BigInteger. I would imagine that the BigInteger problem can be fixed by converting the BigInteger to org.bson.types.ObjectId?

      Comment


      • #4
        You can grab the fix from here if you can't wait for the next release:

        https://github.com/SpringSource/spri...ede96406ecdfe0

        Comment


        • #5
          Looks like only BigDecimal is fixed in that JIRA. However I will see if I can extend the same principle to BigInteger - since its Id I need tosee if the converters will be applied.

          Comment


          • #6
            We tried writing our own custom converter (attached) however it did not work.

            The JIRA fixes problems with non-ID fields where MappingMongoConverter.writeInternal() -> DBObject.put() -> ConversionService.convert() on the object which will utilise our converter. However but for ID fields it just does a straight put() on the object. Thus does not invoke the converter.

            Is this a bug that needs to be logged in JIRA?

            Comment


            • #7
              Just pushed a fixed to the repo and deployed a snapshot. Feel free to give it a try. In case you still encounter issues, please open a ticket in our JIRA .

              [0] https://github.com/SpringSource/spri...eb904a57310edb

              Comment


              • #8
                Thanks for looking at this issue. While your fix in the snapshot version does allow to save 'id' of type BigInteger in MongoDB, it is still unable to retrieve the object back using findOne method with BigInteger id as argument.

                After debugging a bit into the Spring Data code, I suspect the reason is that after your fix, while saving an object, the BigInteger id is converted to String and stored. In writeInternal methid, the conversion types in MappingMongoConverter have been expanded to:
                360. Class<?>[] targetClasses = new Class<?>[] { ObjectId.class, String.class, Object.class };

                However, while retrieving the object using findOne method, the QueryMapper calls the convertObjectId(Object id) method of MappingMongoConverter. This method by default assumes the targetType to be ObjectId.class. And this is where it fails. So the lookup happens on this based on key as id and based on value BigInteger 789 whereas it is stored as String "789". This again leads to the " can't serialize class java.math.BigInteger" exception.

                I think the QueryMapper call could be expanded to something similar to what was done above (may be calling convertObjectId(ObjectId id, Class<T> targetType) method on MappingMongoConverter looping through an array of possible targetType classes).

                So, in the current snapshot, once a BigInteger id has been saved, the only way of retrieving it is by querying the repository with id converted to String.

                Do let us know if you agree with our observations and if a JIRA is needed for this.

                Thanks again for your help.

                I am using:

                Spring-data-mongodb: 1.0.0.BUILD-SNAPSHOT
                spring-data-commons-core: 1.2.0-BUILD-SNAPSHOT

                Comment


                • #9
                  Created DATADOC-247 [0] to track this.

                  [0] https://jira.springsource.org/browse/DATADOC-247

                  Comment


                  • #10
                    I am new to Spring-data-mongodb, and I found that findone problem had be solved in new version.
                    But I found QueryDslPredicateExecutor function using Predicate still has the same problem.
                    (see attachment's test result)

                    Attachment asses MongoLab using follow library:
                    spring-data-mongodb 1.0.0.M5
                    querydsl-mongodb 2.2.5

                    Another question is why it so slow when findAll() to fetch all the collection?

                    can someone explain to me? Thank you.

                    Comment


                    • #11
                      Up to version 2.2.4 Querydsl did not convert parameter values before applying them to queries at all. There's a ticket [0] open for Spring Data to hook into this which will be fixed for the RC.

                      What exactly is "so slow"? If the collection is big, findAll() will of course read all the data and convert each and every document into the the according domain object which might a) take some time and b) consume quite an amount of memory.

                      [0] https://github.com/mysema/querydsl/issues/29

                      Comment


                      • #12
                        Thanks for your reply.

                        There is a testResult.html in the attachment.
                        In this test program.
                        I insert ten documents and findOne() not over 1 sec, but findAll() spends 18 secs to read.

                        So I feel it so slow.(I think the reason maybe due to @DBRef)

                        Comment

                        Working...
                        X