-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
5.0
-
x86
-
windows_xp
FULL PRODUCT VERSION :
ADDITIONAL OS VERSION INFORMATION :
Windows XP
A DESCRIPTION OF THE PROBLEM :
isAssignableFrom checks from assignment of class but somewhat ignore primatives. Is there a method which checks for assignment of classes AND primatives.
What is the issue?
The problem I have is that the method doesn't do what it suggests it
should do and there is no other method which does.
When the method was first written perhaps it was correct behaviour,
however with auto-boxing and reflection it is more accurate to say
Double and double can be assigned to each other.
Why do I need it?
I need to be able to test whether by reflection an object can be
assigned to a field or can be passed as an argument to a method. To do
this I need a test which will say a 'Double' can be used to set a field
of type 'double'. (In fact you cannot pass a double as an object in any
case.)
How can this be addressed?
Currently the only way to address this is to write method which handle
primatives in a way which is consistent with the way Object types are
handled.
The following method caches results to avoid native calls and repeatedly
throwing ClassNotFoundException. However these could be written without
such caching.
private static final Map<Class, Class> PRIMATIVE_MATCH = new
LinkedHashMap<Class, Class>() {
{
put(long.class, Long.class);
put(int.class, Integer.class);
put(double.class, Double.class);
put(short.class, Short.class);
put(byte.class, Byte.class);
put(float.class, Float.class);
put(boolean.class, Boolean.class);
put(char.class, Character.class);
}
};
private static final Map<String, Class> CLASS_LOOKUP = new
ConcurrentHashMap<String, Class>() {
{
for (Class clazz : PRIMATIVE_MATCH.keySet())
put(clazz.getName(), clazz);
}
};
private static final Map<Pair<Class,Class>, Boolean>
IS_ASSIGNABLE_FROM = new ConcurrentHashMap<Pair<Class, Class>,
Boolean>();
public static boolean isAssignableFrom(@NotNull Class class1,
@NotNull Class class2) {
if (class1 == class2 || class1 == Object.class) return true;
Class pclass1 = PRIMATIVE_MATCH.get(class1);
if (pclass1 != null)
return pclass1 == class2;
Class pclass2 = PRIMATIVE_MATCH.get(class2);
if (pclass2 != null)
return pclass1 == class2;
Pair<Class,Class> classPair = new Pair<Class, Class>(class1,
class2);
Boolean ret = IS_ASSIGNABLE_FROM.get(classPair);
if (ret == null)
IS_ASSIGNABLE_FROM.put(classPair, ret =
class1.isAssignableFrom(class2));
return ret;
}
@Nullable public static Class forName(@NotNull String name) {
Class clazz = CLASS_LOOKUP.get(name);
// ConcurrentHashMap doesn't support null values so void.class
is used instead as no value can be of type void.
if (clazz != null) return clazz == void.class ? null : clazz;
Class clazz2;
try {
clazz2 = Class.forName(name);
} catch (ClassNotFoundException ignored) {
clazz2 = void.class;
}
CLASS_LOOKUP.put(name, clazz2);
return clazz2;
}
REGRESSION. Last worked in version mustang
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See unit test below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
That if one class can be assigned to another class isAssignableTo() should return true.
ACTUAL -
It only checks for Objects and exact matches for primatives.
In the source code, these primatives/non-primatives are assigned to one another using regular '=' assignment and via reflection but isAssignableFrom returns false in every case.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import junit.framework.*;
import java.lang.reflect.*;
public class A extends TestCase {
public void test_isAssignment() throws NoSuchFieldException, IllegalAccessException {
PrimativeClass pc = new PrimativeClass();
ObjectClass oc = new ObjectClass((byte) 0, (short) 0, 0, 0L, 0.0f, 0.0, '0');
pc._byte = oc._byte;
pc._short = oc._short;
pc._integer = oc._integer;
pc._long = oc._long;
pc._float = oc._float;
pc._double = oc._double;
pc._char = oc._char;
oc._byte = pc._byte;
oc._short = pc._short;
oc._integer = pc._integer;
oc._long = pc._long;
oc._float = pc._float;
oc._double = pc._double;
oc._char = pc._char;
// copy using reflection.
for(Field f : PrimativeClass.class.getDeclaredFields())
ObjectClass.class.getField(f.getName()).set(oc, f.get(pc));
// copy using reflection.
for(Field f : ObjectClass.class.getDeclaredFields())
PrimativeClass.class.getField(f.getName()).set(pc, f.get(oc));
Class[] class1 = {byte.class, short.class, int.class, long.class, float.class, double.class, char.class};
Class[] class2 = {Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Character.class};
for (int i = 0; i < class1.length; i++) {
System.out.println(class1[i] + " isAssignableFrom( " + class2[i] + ") is " + class1[i].isAssignableFrom(class2[i]));
System.out.println(class2[i] + " isAssignableFrom( " + class1[i] + ") is " + class2[i].isAssignableFrom(class1[i]));
}
}
public static class PrimativeClass {
public byte _byte;
public short _short;
public int _integer;
public long _long;
public float _float;
public double _double;
public char _char;
}
public static class ObjectClass {
public Byte _byte;
public Short _short;
public Integer _integer;
public Long _long;
public Float _float;
public Double _double;
public Character _char;
public ObjectClass(Byte _byte, Short _short, Integer _integer, Long _long, Float _float, Double _double, Character _char) {
this._byte = _byte;
this._short = _short;
this._integer = _integer;
this._long = _long;
this._float = _float;
this._double = _double;
this._char = _char;
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Create own method for check if one class is a primative.
Suggest adding a method which tests whether one class can be assigned to a field with another class.
ADDITIONAL OS VERSION INFORMATION :
Windows XP
A DESCRIPTION OF THE PROBLEM :
isAssignableFrom checks from assignment of class but somewhat ignore primatives. Is there a method which checks for assignment of classes AND primatives.
What is the issue?
The problem I have is that the method doesn't do what it suggests it
should do and there is no other method which does.
When the method was first written perhaps it was correct behaviour,
however with auto-boxing and reflection it is more accurate to say
Double and double can be assigned to each other.
Why do I need it?
I need to be able to test whether by reflection an object can be
assigned to a field or can be passed as an argument to a method. To do
this I need a test which will say a 'Double' can be used to set a field
of type 'double'. (In fact you cannot pass a double as an object in any
case.)
How can this be addressed?
Currently the only way to address this is to write method which handle
primatives in a way which is consistent with the way Object types are
handled.
The following method caches results to avoid native calls and repeatedly
throwing ClassNotFoundException. However these could be written without
such caching.
private static final Map<Class, Class> PRIMATIVE_MATCH = new
LinkedHashMap<Class, Class>() {
{
put(long.class, Long.class);
put(int.class, Integer.class);
put(double.class, Double.class);
put(short.class, Short.class);
put(byte.class, Byte.class);
put(float.class, Float.class);
put(boolean.class, Boolean.class);
put(char.class, Character.class);
}
};
private static final Map<String, Class> CLASS_LOOKUP = new
ConcurrentHashMap<String, Class>() {
{
for (Class clazz : PRIMATIVE_MATCH.keySet())
put(clazz.getName(), clazz);
}
};
private static final Map<Pair<Class,Class>, Boolean>
IS_ASSIGNABLE_FROM = new ConcurrentHashMap<Pair<Class, Class>,
Boolean>();
public static boolean isAssignableFrom(@NotNull Class class1,
@NotNull Class class2) {
if (class1 == class2 || class1 == Object.class) return true;
Class pclass1 = PRIMATIVE_MATCH.get(class1);
if (pclass1 != null)
return pclass1 == class2;
Class pclass2 = PRIMATIVE_MATCH.get(class2);
if (pclass2 != null)
return pclass1 == class2;
Pair<Class,Class> classPair = new Pair<Class, Class>(class1,
class2);
Boolean ret = IS_ASSIGNABLE_FROM.get(classPair);
if (ret == null)
IS_ASSIGNABLE_FROM.put(classPair, ret =
class1.isAssignableFrom(class2));
return ret;
}
@Nullable public static Class forName(@NotNull String name) {
Class clazz = CLASS_LOOKUP.get(name);
// ConcurrentHashMap doesn't support null values so void.class
is used instead as no value can be of type void.
if (clazz != null) return clazz == void.class ? null : clazz;
Class clazz2;
try {
clazz2 = Class.forName(name);
} catch (ClassNotFoundException ignored) {
clazz2 = void.class;
}
CLASS_LOOKUP.put(name, clazz2);
return clazz2;
}
REGRESSION. Last worked in version mustang
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See unit test below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
That if one class can be assigned to another class isAssignableTo() should return true.
ACTUAL -
It only checks for Objects and exact matches for primatives.
In the source code, these primatives/non-primatives are assigned to one another using regular '=' assignment and via reflection but isAssignableFrom returns false in every case.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import junit.framework.*;
import java.lang.reflect.*;
public class A extends TestCase {
public void test_isAssignment() throws NoSuchFieldException, IllegalAccessException {
PrimativeClass pc = new PrimativeClass();
ObjectClass oc = new ObjectClass((byte) 0, (short) 0, 0, 0L, 0.0f, 0.0, '0');
pc._byte = oc._byte;
pc._short = oc._short;
pc._integer = oc._integer;
pc._long = oc._long;
pc._float = oc._float;
pc._double = oc._double;
pc._char = oc._char;
oc._byte = pc._byte;
oc._short = pc._short;
oc._integer = pc._integer;
oc._long = pc._long;
oc._float = pc._float;
oc._double = pc._double;
oc._char = pc._char;
// copy using reflection.
for(Field f : PrimativeClass.class.getDeclaredFields())
ObjectClass.class.getField(f.getName()).set(oc, f.get(pc));
// copy using reflection.
for(Field f : ObjectClass.class.getDeclaredFields())
PrimativeClass.class.getField(f.getName()).set(pc, f.get(oc));
Class[] class1 = {byte.class, short.class, int.class, long.class, float.class, double.class, char.class};
Class[] class2 = {Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Character.class};
for (int i = 0; i < class1.length; i++) {
System.out.println(class1[i] + " isAssignableFrom( " + class2[i] + ") is " + class1[i].isAssignableFrom(class2[i]));
System.out.println(class2[i] + " isAssignableFrom( " + class1[i] + ") is " + class2[i].isAssignableFrom(class1[i]));
}
}
public static class PrimativeClass {
public byte _byte;
public short _short;
public int _integer;
public long _long;
public float _float;
public double _double;
public char _char;
}
public static class ObjectClass {
public Byte _byte;
public Short _short;
public Integer _integer;
public Long _long;
public Float _float;
public Double _double;
public Character _char;
public ObjectClass(Byte _byte, Short _short, Integer _integer, Long _long, Float _float, Double _double, Character _char) {
this._byte = _byte;
this._short = _short;
this._integer = _integer;
this._long = _long;
this._float = _float;
this._double = _double;
this._char = _char;
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Create own method for check if one class is a primative.
Suggest adding a method which tests whether one class can be assigned to a field with another class.