[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-24 Thread Sebb (JIRA)

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

Sebb commented on LANG-1323:


Thanks for the bug URL, very useful.

There are two difficulties with using the bug text as the definition:
1) It has not been accepted, and could be modified.
2) what license covers its use?

AFAICT we cannot use the actual implementation, as that is under the 
GPL+Classpath exception [1]

[1] http://www.apache.org/legal/resolved.html#category-x

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


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-24 Thread Scott Kilpatrick (JIRA)

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

Scott Kilpatrick commented on LANG-1323:


Yeah, that makes sense. I understand that the Java SE doesn't -- _but should!_ 
-- define how to implement {{Type.hashCode}}. There seems to be a years-old JDK 
bug report about this exact issue: 
https://bugs.openjdk.java.net/browse/JDK-7082069.

Given the size and importance of the OpenJDK, however, would it not make sense 
to treat that as the canonical definition of {{Type.hashCode()}}, and modify 
the Commons Lang implementations to adhere to that?

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


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-21 Thread Sebb (JIRA)

[ 
https://issues.apache.org/jira/browse/LANG-1323?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=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}} 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)


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-21 Thread Scott Kilpatrick (JIRA)

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

Scott Kilpatrick commented on LANG-1323:


The Guava stuff was just an _additional example_ of a sneaky manifestation of 
the bug; it's not crucial to the bug. Sorry to have included more than 
necessary in that example.

For posterity, here's the example demonstrating the broken contract, without 
the additional broken use case:

{code:java}
static class OneField {
Map f;
}

@Test
public void testOfBrokenContract() throws NoSuchFieldException
{
// An object of class 
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
final Type openJdkType = 
OneField.class.getDeclaredField("f").getGenericType();

// An object of class 
org.apache.commons.lang3.reflect.TypeUtils.ParameterizedTypeImpl
final Type apacheType = TypeUtils.parameterize(Map.class, String.class, 
Integer.class);

// These two objects are equal...
Assert.assertTrue(openJdkType.equals(apacheType));
Assert.assertTrue(apacheType.equals(openJdkType));

// ... but their hash codes are not the same
Assert.assertFalse(openJdkType.hashCode() == apacheType.hashCode());
}
{code}

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


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-21 Thread Sebb (JIRA)

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

Sebb commented on LANG-1323:


bq. the hashCode in TypeUtils is inconsistent with the hashCode in the OpenJDK 
and

This is not a requirement

bq. the contract of Object.hashCode requires that their hashCode's be 
consistent since their equals are consistent.

Agreed.

But the unit test you provided only shows that the ImmutableSet implementation 
of hashCode/equals is broken.
It does not say anything about TypeUtils.
Or if there is a problem with TypeUtils, this needs to be exposed by a unit 
test that only uses the LANG classes.

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


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-21 Thread Scott Kilpatrick (JIRA)

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

Scott Kilpatrick commented on LANG-1323:


[~s...@apache.org]: 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: 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}} 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)


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-21 Thread Scott Kilpatrick (JIRA)

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

Scott Kilpatrick commented on LANG-1323:


Here's an example in JUnit:

{code:java}
static class OneField {
Map 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}} 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)


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-21 Thread Sebb (JIRA)

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

Sebb commented on LANG-1323:


Are you saying that some of the TypeUtils classes have incompatible equals() 
and hashCode() implementations?

If so, then that is clearly a bug. A test case would be useful.

However it is OK to provide a hashCode() implementation that is different from 
the 'standard' implementation, so long as it is consistent with the equals() 
defintion.

For example, if the hashCode() implementation always returns 42.
It's a terrible hash, but it does not break the hash/equals contract.
There is no requirement for unequal objects to have different hashes.

Indeed any class that assumes that equal hashCodes mean equal Objects is broken.
Object.hashCode() can produce equal hashCodes for unequal objects.

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


[jira] [Commented] (LANG-1323) Type implementations in TypeUtils compute hash code that breaks Object.equals() with Sun's OpenJDK

2017-04-21 Thread Scott Kilpatrick (JIRA)

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

Scott Kilpatrick commented on LANG-1323:


Hash code implementation comparisons:

* {{GenericArrayTypeImpl}}: 
[TypeUtils|https://git-wip-us.apache.org/repos/asf?p=commons-lang.git;a=blob;f=src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java;h=8db6ca47813389708781c5117f3109865c815d2c;hb=HEAD#l134]
 vs. 
[OpenJDK|http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/reflect/generics/reflectiveObjects/GenericArrayTypeImpl.java#l89]

* {{ParameterizedTypeImpl}}: 
[TypeUtils|https://git-wip-us.apache.org/repos/asf?p=commons-lang.git;a=blob;f=src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java;h=8db6ca47813389708781c5117f3109865c815d2c;hb=HEAD#l203]
 vs. 
[OpenJDK|http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java#l198]

* {{WildcardTypeImpl}}: 
[TypeUtils|https://git-wip-us.apache.org/repos/asf?p=commons-lang.git;a=blob;f=src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java;h=8db6ca47813389708781c5117f3109865c815d2c;hb=HEAD#l270]
 vs. 
[OpenJDK|http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/reflect/generics/reflectiveObjects/WildcardTypeImpl.java#l224]

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