[
https://issues.apache.org/jira/browse/LANG-1323?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15979569#comment-15979569
]
Sebb commented on LANG-1323:
----------------------------
I see what you mean now.
It seems that there are additional equals/hashCode requirements for instances
of the Type interface hierarchy which go beyond the normal equals/hashCode
contract.
Unfortunately the requirements don't appear to be fully documented.
The ParameterizedType Javadoc specifies how the equals() method is to be
implemented, but it does not say anything about the hashCode requirements.
The variables to be compared are known, so the equals() method is easily
written from the Javadoc.
However there are potentially multiple ways to derive the hashCode.
I don't see how it's possible to code alternate implementations from the
Javadoc alone.
So it looks to me as though the Javadoc is incomplete.
If the OpenJDK source were not available it would be impossible to implement an
object that conforms to the ParameterizedType Javadoc and the equals/hashCode
contract.
> Type implementations in TypeUtils compute hash code that breaks
> Object.equals() with Sun's OpenJDK
> --------------------------------------------------------------------------------------------------
>
> Key: LANG-1323
> URL: https://issues.apache.org/jira/browse/LANG-1323
> 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|http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/reflect/generics/reflectiveObjects]
> 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
(v6.3.15#6346)