[JAVA-1785] ObjectId.compareTo() returns wrong response Created: 29/Apr/15  Updated: 18/Nov/18  Resolved: 30/Apr/15

Status: Closed
Project: Java Driver
Component/s: BSON
Affects Version/s: 3.0.0
Fix Version/s: 3.0.1

Type: Bug Priority: Major - P3
Reporter: Pavlos Kranas Assignee: Ross Lawley
Resolution: Done Votes: 0
Labels: regression
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

JDK 7.0_51


Attachments: HTML File ObjectId.java    
Backwards Compatibility: Major Change

 Description   

I have 2 long values [100, 200], with which I create two ObjectId objects, using a byte array
byte1 = byte [] bytes = ByteBuffer.allocate(12).putLong(value1).put(new byte[4]).array()
objectId1 = ObjectId(byte1)

This constructs the following two ObjectIds:
obj1 = 000000000000006400000000
obj2 = 00000000000000c800000000

When i try to compare: obj1.compareTo(obj2)<0 the result is false
This happens because obj1's processIdentifier value (bytes "6400") is set to value "25600", while the obj2's processIdentifier value (bytes "c800") is set to the signed "-14336".
So the comparison "x = processIdentifier - other.processIdentifier;" is positive and obj1.compareTo(obj2)<0 returns false.

In v2.x.x versions of the driver, there was a "_compareUnsigned" operation, for handling these comparisons.

Is this a bug or this is the way it should work now?



 Comments   
Comment by Jeffrey Yemin [ 05/May/15 ]

Closed for 3.0.1 release.

Comment by Githook User [ 30/Apr/15 ]

Author:

{u'username': u'rozza', u'name': u'Ross Lawley', u'email': u'ross.lawley@gmail.com'}

Message: Fix ObjectId compareTo for Java 6

JAVA-1785
Branch: master
https://github.com/mongodb/mongo-java-driver/commit/1a0549c8d74925d02df5a56ea9ee44a0d71751c9

Comment by Githook User [ 30/Apr/15 ]

Author:

{u'username': u'rozza', u'name': u'Ross Lawley', u'email': u'ross.lawley@gmail.com'}

Message: Fix ObjectId compareTo for Java 6

JAVA-1785
Branch: 3.0.x
https://github.com/mongodb/mongo-java-driver/commit/0db294195fb3adb31caf7bc75b01d716a7dfc6ab

Comment by Githook User [ 30/Apr/15 ]

Author:

{u'username': u'rozza', u'name': u'Ross Lawley', u'email': u'ross.lawley@gmail.com'}

Message: Fix regression in ObjectId.compareTo

Now checks the byte array unsigned int values
JAVA-1785
Branch: master
https://github.com/mongodb/mongo-java-driver/commit/19e6f77e55bce8837c70da05df358eb7114d8c48

Comment by Ross Lawley [ 30/Apr/15 ]

Thanks for reporting pkranas. This has been fixed and will be released in 3.0.1

Comment by Githook User [ 30/Apr/15 ]

Author:

{u'username': u'rozza', u'name': u'Ross Lawley', u'email': u'ross.lawley@gmail.com'}

Message: Fix regression in ObjectId.compareTo

Now checks the byte array unsigned int values
JAVA-1785
Branch: 3.0.x
https://github.com/mongodb/mongo-java-driver/commit/3a4b24ecea03b76d7c3dac1398d94a6ef5a6ceed

Comment by Ross Lawley [ 29/Apr/15 ]

pkranas, my apologies - I do believe this is a regression and counter to how the server compares the ObjectId's.

Will confirm and update shortly.

Comment by Pavlos Kranas [ 29/Apr/15 ]

Hi Ross,

Thanx for your quick reply

I understood what u wrote to me, however my point was that until
v.13.0, the ObjectId's compareTo() was using unsigned short types for
making the comparisons between ObjectID's subtypes. The
'_compareUnsigned' method was invoked in order to explicitly transform a
signed type to unsigned and then perform the comparison (see line 374,
387 of the attached).

So from your answer I can assume that this will no longer stand for
v3.x.x and I have to provide only signed values for the various
ObjectId's subtypes, right?

Thanx in advance for your time,
Pavlos

Comment by Ross Lawley [ 29/Apr/15 ]

Hi pkranas,

In 3.0.0 ObjectId was bought up to specification in : JAVA-749.

An ObjectId is a 12-byte BSON type, constructed using:

  • a 4-byte value representing the seconds since the Unix epoch,
  • a 3-byte machine identifier,
  • a 2-byte process id, and
  • a 3-byte counter, starting with a random value.

So from your example the bytes are:

byte1 = new byte[]{0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0}
byte2 = new byte[]{0, 0, 0, 0, 0, 0,  -56, 0, 0, 0, 0, 0}

So from that we get the respective processIdentifier's and so I would expect that:

assert(objectId1.compareTo(objectId2) > 0);

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