Skip to content

Different Queries, same hashCodes #4032

Not planned
@kusamau

Description

@kusamau

Consider two org.springframework.data.mongodb.core.query.Query instances almost identical except for one projection field which is

  • included in one query
  • excluded in the other query

then the following test fails

Assertions.assertNotEquals(queryWithExclude.hashCode(), queryWithInclude.hashCode());

Unit Test

    @Test
    public void hashMapQueryTest() {
        Query queryWithExclude = new Query();
        queryWithExclude.fields().exclude("key1");
        queryWithExclude.fields().exclude("key2");

        Query queryWithInclude = new Query();
        queryWithInclude.fields().include("key1");
        queryWithInclude.fields().include("key2");

        Assertions.assertNotEquals(queryWithExclude.hashCode(), queryWithInclude.hashCode());
    }

Comments
The problem can be drilled down to the Field.hashCode()

ObjectUtils.nullSafeHashCode(this.criteria);

which seems to fails due to the HashMap implementation itself as proved by the following test

    @Test
    public void hashMapZeroOneTest() {
        HashMap<String, Integer> fieldZero = new HashMap<>();
        fieldZero.put("key1", 0);
        fieldZero.put("key2", 0);

        HashMap<String, Integer> fieldOne = new HashMap<>();
        fieldOne.put("key1", 1);
        fieldOne.put("key2", 1);

        Assertions.assertNotEquals(fieldZero.hashCode(), fieldOne.hashCode());
    }

however tests with other numbers than 0 or 1 works.

To conclude, the problem seem related to the use of 0 and 1 in the Field.criteria which then are translated according to the mongo projection syntax. Possible solution could be to replace in the Field class 0/1 used by include/exclude with enum INCLUDE/EXCLUDE values and consequently modify up to various get[Query|Field]Object().

Comments?

Regards,
Maurizio

Activity

13wjdgk

13wjdgk commented on Nov 10, 2024

@13wjdgk

PR : #4831

mp911de

mp911de commented on Nov 11, 2024

@mp911de
Member

hashCode is not required to be unequal for two objects that do not equal each other.

Taking a step back, what problem are you trying to solve? Looking at the attached pull request, performance gets worse by an order of magnitude by introducing allocations (toString rendering).

13wjdgk

13wjdgk commented on Nov 12, 2024

@13wjdgk

@mp911de
According to the official Java documentation, equal objects must have the same hash code. However, in the current query example, non-equal objects are returning the same hash code.

If the toString() method is inefficient, could you review the alternative method I suggested in the PR comments?

Thank you for your comment!

injae-kim

injae-kim commented on Nov 12, 2024

@injae-kim

Taking a step back, what problem are you trying to solve?

Yes hashCode is not required to be unequal for not equal objects.

But specially on Query, cause it uses hashMap.put(key, 0 or 1) on .include() and .exclude(), same hashCode can be generated too easily on different query.

So how about using hashMap.toString() or overload hashCode() to not easily generate same hashCode of Query?

mp911de

mp911de commented on Nov 12, 2024

@mp911de
Member

But specially on Query, cause it uses hashMap.put(key, 0 or 1) on .include() and .exclude(), same hashCode can be generated too easily on different query.

Are you running into a performance issue or a bug? What problem are you trying to solve? Same hashCodes are only a symptom.

9 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    Different Queries, same hashCodes · Issue #4032 · spring-projects/spring-data-mongodb