commons-issues mailing list archives

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


Scott Kilpatrick commented on LANG-1323:

[]: Right, the contract does not say anything about two objects that produce
equal hash codes. But it does indeed say something about two objects that are equal, i.e.,
that they must produce the same hash code. So I'm not saying that anything in {{TypeUtils}}
is inconsistent _within itself_, but that

# the {{hashCode}} in {{TypeUtils}} is inconsistent with the {{hashCode}} in the OpenJDK and
# the contract of {{Object.hashCode}} requires that their {{hashCode}}'s be consistent since
their {{equals}} are consistent.

> Type implementations in TypeUtils compute hash code that breaks Object.equals() with
Sun's OpenJDK
> --------------------------------------------------------------------------------------------------
>                 Key: LANG-1323
>                 URL:
>             Project: Commons Lang
>          Issue Type: Bug
>          Components: lang.reflect.*
>    Affects Versions: 3.2, 3.5
>         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:
> {code:java}
> TypeUtils.parameterize(Map.class, String.class, Integer.class)
> {code}
> 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