[ 
https://issues.apache.org/jira/browse/LANG-1323?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15979111#comment-15979111
 ] 

Scott Kilpatrick edited comment on LANG-1323 at 4/21/17 6:30 PM:
-----------------------------------------------------------------

Here's an example in JUnit:

{code:java}
    static class OneField {
        Map<String, Integer> f;
    }

    @Test
    public void test() throws NoSuchFieldException
    {
        final Type openJdkType = 
OneField.class.getDeclaredField("f").getGenericType();
        final Type apacheType = TypeUtils.parameterize(Map.class, String.class, 
Integer.class);
        Assert.assertTrue(openJdkType.equals(apacheType));
        Assert.assertTrue(apacheType.equals(openJdkType));
        Assert.assertFalse(openJdkType.hashCode() == apacheType.hashCode());

        // Example with Guava's ImmutableSet and Iterables, which for N > 1 uses
        // hash code for set equality.
        final Type other = OneField.class;
        final ImmutableSet<Type> c1 = ImmutableSet.of(openJdkType, other);
        final ImmutableSet<Type> c2 = ImmutableSet.of(apacheType, other);
        Assert.assertFalse(c1.equals(c2));
        Assert.assertFalse(c2.equals(c1));
        Assert.assertTrue(c1.size() == c2.size());
        Assert.assertTrue(Iterables.elementsEqual(c1, c2));
    }
{code}

Is this not a violation of the contract on {{Object.hashCode()}} that I quoted 
above? Here are two objects that are equal according to the {{equals(Object)}} 
method, but calling the {{hashCode}} method on each of the two objects produces 
different integer results.


was (Author: skilpat):
Here's an example in JUnit:

{code:java}
    static class OneField {
        Map<String, Integer> f;
    }

    @Test
    public void test() throws NoSuchFieldException {
        final Type openJdkType = 
OneField.class.getDeclaredField("f").getGenericType();
        final Type apacheType = TypeUtils.parameterize(Map.class, String.class, 
Integer.class);
        Assert.assertTrue(openJdkType.equals(apacheType) && 
apacheType.equals(openJdkType));
        Assert.assertFalse(openJdkType.hashCode() == apacheType.hashCode());
    }
{code}

Is this not a violation of the contract on {{Object.hashCode()}} that I quoted 
above? Here are two objects that are equal according to the {{equals(Object)}} 
method, but calling the {{hashCode}} method on each of the two objects produces 
different integer results.

> 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)

Reply via email to