-
Bug
-
Resolution: Unresolved
-
P3
-
8
-
x86_64
-
linux
FULL PRODUCT VERSION :
1.8.0
ADDITIONAL OS VERSION INFORMATION :
Linux ivostmaina 3.13.6-gentoo #1 SMP Thu Mar 20 02:22:16 CET 2014 x86_64 AMD FX(tm)-8350 Eight-Core Processor AuthenticAMD GNU/Linux
A DESCRIPTION OF THE PROBLEM :
From the description of the interface TypeVariable:
Multiple objects may be instantiated at run-time to represent a given type variable. Even though a type variable is created only once, this does not imply any requirement to cache instances representing the type variable. However, all instances representing a type variable must be equal() to each other. As a consequence, users of type variables must not rely on the identity of instances of classes implementing this interface.
But in the actual implementation TypeVariableImpl.java (http://hg.openjdk.java.net/jdk8/tl/jdk/file/183a8c520b4a/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java) I see that equals() behaves wrong.
@Override
public boolean equals(Object o) {
if (o instanceof TypeVariable &&
o.getClass() == TypeVariableImpl.class) {
TypeVariable<?> that = (TypeVariable<?>) o;
GenericDeclaration thatDecl = that.getGenericDeclaration();
String thatName = that.getName();
return Objects.equals(genericDeclaration, thatDecl) &&
Objects.equals(name, thatName);
} else
return false;
}
The Test "o.getClass() == TypeVariableImpl.class" violates the requirement from the description "As a consequence, users of type variables must not rely on the identity of instances of classes implementing this interface."
REGRESSION. Last worked in version 8
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
@Test
@SuppressWarnings("rawtypes")
public void java8_typevariable_equals_and_hashcode() {
class MyClass<T> {
}
final TypeVariable<Class<MyClass>> v = MyClass.class.getTypeParameters()[0];
final TypeVariable<Class<MyClass>> vcp = new TypeVariable<Class<MyClass>>() {
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return v.getAnnotation(annotationClass);
}
@Override
public Annotation[] getAnnotations() {
return v.getAnnotations();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return v.getDeclaredAnnotations();
}
@Override
public Type[] getBounds() {
return v.getBounds();
}
@Override
public Class<MyClass> getGenericDeclaration() {
return v.getGenericDeclaration();
}
@Override
public String getName() {
return v.getName();
}
@Override
public AnnotatedType[] getAnnotatedBounds() {
return v.getAnnotatedBounds();
}
@Override
public int hashCode() {
return Objects.hashCode(getName()) ^ Objects.hashCode(getGenericDeclaration());
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof TypeVariable))
return false;
TypeVariable<?> other = (TypeVariable<?>) obj;
return ObjectUtils.equals(getGenericDeclaration(), other.getGenericDeclaration())
&& ObjectUtils.equals(getName(), other.getName());
}
};
assertEquals(v.hashCode(), vcp.hashCode());
assertEquals(vcp, v);
assertEquals(v, vcp); // FAILS HERE
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No nice workaround.
1.8.0
ADDITIONAL OS VERSION INFORMATION :
Linux ivostmaina 3.13.6-gentoo #1 SMP Thu Mar 20 02:22:16 CET 2014 x86_64 AMD FX(tm)-8350 Eight-Core Processor AuthenticAMD GNU/Linux
A DESCRIPTION OF THE PROBLEM :
From the description of the interface TypeVariable:
Multiple objects may be instantiated at run-time to represent a given type variable. Even though a type variable is created only once, this does not imply any requirement to cache instances representing the type variable. However, all instances representing a type variable must be equal() to each other. As a consequence, users of type variables must not rely on the identity of instances of classes implementing this interface.
But in the actual implementation TypeVariableImpl.java (http://hg.openjdk.java.net/jdk8/tl/jdk/file/183a8c520b4a/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java) I see that equals() behaves wrong.
@Override
public boolean equals(Object o) {
if (o instanceof TypeVariable &&
o.getClass() == TypeVariableImpl.class) {
TypeVariable<?> that = (TypeVariable<?>) o;
GenericDeclaration thatDecl = that.getGenericDeclaration();
String thatName = that.getName();
return Objects.equals(genericDeclaration, thatDecl) &&
Objects.equals(name, thatName);
} else
return false;
}
The Test "o.getClass() == TypeVariableImpl.class" violates the requirement from the description "As a consequence, users of type variables must not rely on the identity of instances of classes implementing this interface."
REGRESSION. Last worked in version 8
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
@Test
@SuppressWarnings("rawtypes")
public void java8_typevariable_equals_and_hashcode() {
class MyClass<T> {
}
final TypeVariable<Class<MyClass>> v = MyClass.class.getTypeParameters()[0];
final TypeVariable<Class<MyClass>> vcp = new TypeVariable<Class<MyClass>>() {
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return v.getAnnotation(annotationClass);
}
@Override
public Annotation[] getAnnotations() {
return v.getAnnotations();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return v.getDeclaredAnnotations();
}
@Override
public Type[] getBounds() {
return v.getBounds();
}
@Override
public Class<MyClass> getGenericDeclaration() {
return v.getGenericDeclaration();
}
@Override
public String getName() {
return v.getName();
}
@Override
public AnnotatedType[] getAnnotatedBounds() {
return v.getAnnotatedBounds();
}
@Override
public int hashCode() {
return Objects.hashCode(getName()) ^ Objects.hashCode(getGenericDeclaration());
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof TypeVariable))
return false;
TypeVariable<?> other = (TypeVariable<?>) obj;
return ObjectUtils.equals(getGenericDeclaration(), other.getGenericDeclaration())
&& ObjectUtils.equals(getName(), other.getName());
}
};
assertEquals(v.hashCode(), vcp.hashCode());
assertEquals(vcp, v);
assertEquals(v, vcp); // FAILS HERE
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No nice workaround.
- relates to
-
JDK-8031984 sun.reflect.generics.reflectiveObjects.TypeVariableImpl does not honor equals
-
- Closed
-