Scott Kilpatrick created LANG-1323:
--------------------------------------

             Summary: 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.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|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)

Reply via email to