commons-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Scott Kilpatrick (JIRA)" <>
Subject [jira] [Created] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK
Date Fri, 21 Apr 2017 15:55:04 GMT
Scott Kilpatrick created LANG-1323:

             Summary: Type implementations in TypeUtils compute hash code that breaks Object.equals()
with Sun's OpenJDK
                 Key: LANG-1323
             Project: Commons Lang
          Issue Type: Bug
          Components: lang.reflect.*
    Affects Versions: 3.5, 3.2
         Environment: Sun OpenJDK
            Reporter: Scott Kilpatrick
            Priority: Minor

{{TypeUtils}} in {{lang.reflect}} provides convenient methods for creating objects of the
interface {{Type}}. Those objects are defined by the following classes:

* ParameterizedTypeImpl (implements {{ParameterizedType}})
* WildcardTypeImpl (implements {{WildcardType}})
* GenericArrayTypeImpl (implements {{GenericArrayType}})

Similarly, there are corresponding classes, which implement the same interfaces, defined in
one's particular JDK. And it's these latter classes that are instantiated when you get objects
of type {{Type}} via reflection. Let's call these the "internal {{Type}} implementations."
In the case of Sun's OpenJDK, [they are defined|]
in package {{sun.reflect.generics.reflectiveObjects}}.

Each of the {{TypeUtils}} classes implements {{Object.equals(Object)}} in a general way that's
compatible with the internal {{Type}} implementations. For example, if I access a field declared
with type {{Map<String, Integer>}} and get its generic type, via {{Field.getGenericType()}},
then that will be equal to the {{TypeUtils}} object returned by:
TypeUtils.parameterize(Map.class, String.class, Integer.class)
That's what I'd expect, so that's great.

However, the {{TypeUtils}} classes implement their {{Object.hashCode()}} method in a _different_
way from the corresponding implementations in Sun OpenJDK implementations. That's not so surprising,
_but it breaks the contract of {{Object.hashCode()}}_:

bq. If two objects are equal according to the {{equals(Object)}} method, then calling the
{{hashCode}} method on each of the two objects must produce the same integer result.

In other words, the two {{Type}} objects above will both consider themselves {{equals}} to
each other, but they have different hash codes.

One example of a negative consequence of this problem is a collection class that implements
its equality (to other collections) by checking hash codes of its elements, e.g., Guava's
immutable collections. If you have {{Type}} objects in those collections, with {{TypeUtils}}
{{Type}} objects in {{c1}} and Sun OpenJDK {{Type}} objects in {{c2}}, you will see that {{c1.equals(c2)}}
returns {{false}} -- because their elements don't all have the same hash codes -- even though
those elements are all considered equal.

This message was sent by Atlassian JIRA

View raw message