[JAVA-416] Using an Array to create a DBObject breaks .equals and .hashcode Created: 16/Aug/11 Updated: 03/Apr/14 Resolved: 23/Jan/14 |
|
| Status: | Closed |
| Project: | Java Driver |
| Component/s: | API |
| Affects Version/s: | 2.6.5 |
| Fix Version/s: | 2.12.0, 3.0.0 |
| Type: | Bug | Priority: | Minor - P4 |
| Reporter: | Brandon Hudgeons | Assignee: | Jeffrey Yemin |
| Resolution: | Done | Votes: | 1 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Environment: |
All Java |
||
| Issue Links: |
|
||||||||||||||||||||||||
| Backwards Compatibility: | Fully Compatible | ||||||||||||||||||||||||
| Description |
|
Using a Java Array to store information in a DBObject breaks .equals and .hashcode:
Using a List to store the equivalent object does not:
Of course, the two objects are absolutely equal whether they are constructed with an Array or a List:
The fix should just be to store any collection that will end up as a BSON array internally as a java List. |
| Comments |
| Comment by Graham Thomson [ 27/Feb/14 ] |
|
Worked fine for me! Thanks, Graham. |
| Comment by Jeffrey Yemin [ 27/Feb/14 ] |
|
Hi there, Interested parties can test the fix with 2.12.0-rc0, available either on github or Maven Central. Any takers? Thanks, |
| Comment by Jeffrey Yemin [ 23/Jan/14 ] |
|
Fixed this in a fairly general way. Instead of trying to check equality correctly for every possible type, the equals method instead encodes both documents as BSON and checks the equality of the byte arrays. The hashCode method, to fulfill its contract, takes the hash of the encoded BSON. |
| Comment by Githook User [ 23/Jan/14 ] |
|
Author: {u'username': u'jyemin', u'name': u'Jeff Yemin', u'email': u'jeff.yemin@10gen.com'}Message: |
| Comment by Githook User [ 22/Jan/14 ] |
|
Author: {u'username': u'jyemin', u'name': u'Jeff Yemin', u'email': u'jeff.yemin@10gen.com'}Message: |
| Comment by Oliver Gierke [ 23/Aug/11 ] |
|
You're right. But currently arrays cannot be used at all if you rely on equals and hashCode. |
| Comment by Brandon Hudgeons [ 22/Aug/11 ] |
|
Oliver, that would work if both dbObjects held arrays. (What you suggest still should be done, but it doesn't fix the specific problem we're talking about.) We want dbObject1.put("key", anArray); dbObject1.equals(dbObject2); // iff anArray and aList hold the same items |
| Comment by Oliver Gierke [ 21/Aug/11 ] |
|
For the Java side of things this can easily be fixed by using Arrays.equals(left, right). the equals(…) methods simply needs another if clause. The {hasCode()}} method should be adapted as well. |
| Comment by Brandon Hudgeons [ 19/Aug/11 ] |
|
I'm rethinking this now ... maybe the best thing to do is to leave the Java driver as-is. If you use Java, you have to deal with some unfortunate type nonsense (like Int(1) != Long(1)). In Scala, there is all kinds of precedent for engineering == and ## to mask the underlying Java ugliness (like 1 == 1L). Probably best just to fix it there. |
| Comment by Brandon Hudgeons [ 18/Aug/11 ] |
|
BasicDBObject descends from java.util.AbstractMap, so you'd expect dbObject.put("key",x); This is, of course, inconsistent with the desire to have two dbObjects compare as equal if they would be represented by an equivalent document in mongodb but were created with different object types. Two ways I see to address the issue: 1. make a well-documented exception to the above Map interface expectations when the value is a collection. Any time you put a collection value of any type, it will be stored as a DBList. This wouldn't break any explicit interface requirement (since BasicDBObject descends from LinkedHashMap<String,Object>), and I can't imagine that many, if any, clients need an explicit return type for collection values after they are stored and before they are saved/retrieved. If you did #2, the only difference between a user-created dbObject and a driver-created dbObject would be what you get back on a .get("collectionkey"). If you did #1, there'd be no difference (at least in this case). I'd be happy to take a crack at either. |
| Comment by Brendan W. McAdams [ 16/Aug/11 ] |
|
This may pose a more complex issue ... Comparing two dbObjects. If it was created on the userspace side and not saved to MongoDB yet, the Array is likely to be represented as an Array primitive. But once it has been sent to MongoDB and retrieved from there it will be represented as a DBList. These two things should probably compare as equal. What if they use a java.util.List or something else, as well?! |
| Comment by Brendan W. McAdams [ 16/Aug/11 ] |
|
The bug was reported with Scala sample code originally but it is an issue for both Java and Scala users. I'm going to create a scala side fix for SCALA-42, and backport a Java version as well against this bug. |