Details
-
Bug
-
Status: Resolved
-
P3
-
Resolution: Not an Issue
-
7u51
-
None
-
windows_7
Description
FULL PRODUCT VERSION :
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Windows 7 Enterprise
A DESCRIPTION OF THE PROBLEM :
sun.reflect.generics.reflectiveObjects.TypeVariableImpl does not honor equals in the same way that it did in update 45. It now checks the parameter to the equals method to ensure that it is an instance of TypeVariableImpl. I've attached a simple JUNIT 4 test that reproduces this bug.
REGRESSION. Last worked in version 7u45
ADDITIONAL REGRESSION INFORMATION:
sun.reflect.generics.reflectiveObjects.TypeVariableImpl#equals now checks to make sure that the value passed in is of exactly the same class. This was not the case in update 45 and has broken a significant portion of our application.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Subclass java.lang.reflect.TypeVariable and attempt to compare with an instance of sun.reflect.generics.reflectiveObjects.TypeVariableImpl were both objects return the same generic declaration and name. This method will return true subclass.equals(TypeVariableImpl) but false for TypeVariableImpl.equals(subclass).
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The equals method should return true in both cases.
ACTUAL -
The equals method should returns true in only 1 case.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
There is no associated error message.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package test;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import org.hamcrest.core.Is;
import org.junit.Assert;
import org.junit.Test;
public class BugTest {
// -------------------------- OTHER METHODS --------------------------
/**
* This tests a brutal bug in Java 7 update 51.
*/
@Test
public void testEquals() throws NoSuchMethodException {
Type actualType = A.class.getTypeParameters()[0];
Type expectedType = new TypeVariableImplementation<>(A.class, "Y");
Assert.assertThat(actualType, Is.is(expectedType));
Assert.assertThat(expectedType, Is.is(actualType));
}
// -------------------------- INNER CLASSES --------------------------
interface A<Y> {
// -------------------------- OTHER METHODS --------------------------
Y getY();
}
private static class TypeVariableImplementation<GenericDeclarationType extends GenericDeclaration>
implements TypeVariable<GenericDeclarationType> {
// ------------------------------ FIELDS ------------------------------
private Type[] bounds;
private GenericDeclarationType declaration;
private String name;
// --------------------------- CONSTRUCTORS ---------------------------
TypeVariableImplementation(GenericDeclarationType declaration, String name, Type... bounds) {
this.bounds = bounds.clone();
this.declaration = declaration;
this.name = name;
}
// --------------------- GETTER / SETTER METHODS ---------------------
@Override
public String getName() {
return name;
}
// ------------------------ CANONICAL METHODS ------------------------
@Override
public boolean equals(Object value) {
return value instanceof TypeVariable && name.equals(((TypeVariable<?>) value).getName()) &&
declaration.equals(((TypeVariable<?>) value).getGenericDeclaration());
}
@Override
public int hashCode() {
return declaration.hashCode() ^ name.hashCode();
}
@Override
public String toString() {
return name;
}
// ------------------------ INTERFACE METHODS ------------------------
// --------------------- Interface TypeVariable ---------------------
@Override
public Type[] getBounds() {
return bounds.clone();
}
@Override
public GenericDeclarationType getGenericDeclaration() {
return declaration;
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Our only work around is to check for instances of TypeVariableImpl and flip the equals comparison if the TypVariable instance would appear on the left hand side.
SUPPORT :
YES
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Windows 7 Enterprise
A DESCRIPTION OF THE PROBLEM :
sun.reflect.generics.reflectiveObjects.TypeVariableImpl does not honor equals in the same way that it did in update 45. It now checks the parameter to the equals method to ensure that it is an instance of TypeVariableImpl. I've attached a simple JUNIT 4 test that reproduces this bug.
REGRESSION. Last worked in version 7u45
ADDITIONAL REGRESSION INFORMATION:
sun.reflect.generics.reflectiveObjects.TypeVariableImpl#equals now checks to make sure that the value passed in is of exactly the same class. This was not the case in update 45 and has broken a significant portion of our application.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Subclass java.lang.reflect.TypeVariable and attempt to compare with an instance of sun.reflect.generics.reflectiveObjects.TypeVariableImpl were both objects return the same generic declaration and name. This method will return true subclass.equals(TypeVariableImpl) but false for TypeVariableImpl.equals(subclass).
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The equals method should return true in both cases.
ACTUAL -
The equals method should returns true in only 1 case.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
There is no associated error message.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package test;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import org.hamcrest.core.Is;
import org.junit.Assert;
import org.junit.Test;
public class BugTest {
// -------------------------- OTHER METHODS --------------------------
/**
* This tests a brutal bug in Java 7 update 51.
*/
@Test
public void testEquals() throws NoSuchMethodException {
Type actualType = A.class.getTypeParameters()[0];
Type expectedType = new TypeVariableImplementation<>(A.class, "Y");
Assert.assertThat(actualType, Is.is(expectedType));
Assert.assertThat(expectedType, Is.is(actualType));
}
// -------------------------- INNER CLASSES --------------------------
interface A<Y> {
// -------------------------- OTHER METHODS --------------------------
Y getY();
}
private static class TypeVariableImplementation<GenericDeclarationType extends GenericDeclaration>
implements TypeVariable<GenericDeclarationType> {
// ------------------------------ FIELDS ------------------------------
private Type[] bounds;
private GenericDeclarationType declaration;
private String name;
// --------------------------- CONSTRUCTORS ---------------------------
TypeVariableImplementation(GenericDeclarationType declaration, String name, Type... bounds) {
this.bounds = bounds.clone();
this.declaration = declaration;
this.name = name;
}
// --------------------- GETTER / SETTER METHODS ---------------------
@Override
public String getName() {
return name;
}
// ------------------------ CANONICAL METHODS ------------------------
@Override
public boolean equals(Object value) {
return value instanceof TypeVariable && name.equals(((TypeVariable<?>) value).getName()) &&
declaration.equals(((TypeVariable<?>) value).getGenericDeclaration());
}
@Override
public int hashCode() {
return declaration.hashCode() ^ name.hashCode();
}
@Override
public String toString() {
return name;
}
// ------------------------ INTERFACE METHODS ------------------------
// --------------------- Interface TypeVariable ---------------------
@Override
public Type[] getBounds() {
return bounds.clone();
}
@Override
public GenericDeclarationType getGenericDeclaration() {
return declaration;
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Our only work around is to check for instances of TypeVariableImpl and flip the equals comparison if the TypVariable instance would appear on the left hand side.
SUPPORT :
YES
Attachments
Issue Links
- relates to
-
JDK-8039163 Bad TypeVariable.equals() method implementation in TypeVariableImpl
-
- Open
-