JDK-6456930 : Class.cast does not work for primitive types
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 5.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86
  • Submitted: 2006-08-03
  • Updated: 2012-09-28
Related Reports
Relates :  
Relates :  
Relates :  
Description
---%<---
public class ClassCastPrimitiveTest {
    public static void main(String[] _t) {
        Class<Integer> c = Integer.class;
        int i = c.cast(17);
        c = Integer.TYPE;
        i = c.cast(17);
    }
}
---%<---

compiles but produces

---%<---
java version "1.6.0-rc"
Java(TM) SE Runtime Environment (build 1.6.0-rc-b93)
Java HotSpot(TM) Client VM (build 1.6.0-rc-b93, mixed mode, sharing)

Exception in thread "main" java.lang.ClassCastException
        at java.lang.Class.cast(Class.java:2989)
        at ClassCastPrimitiveTest.main(ClassCastPrimitiveTest.java:6)
---%<---

I find this unexpected. JDK 5's autoboxing makes it simple to interconvert primitive and wrapper types, yet here they behave differently. Note in particular that cast applied to an Integer (after autoboxing) on an instance of Class<Integer> fails.

Naturally you would not intentionally pass the primitive type constant if you were expecting for cast(...) to be called. But if you are working with reflection, this situation arises. Example:

PropertyDescriptor p = ...;
Class<?> type = p.getPropertyType();
Object newvalue = ...;
try {
    type.cast(newvalue);
} catch (ClassCastException x) {
    return;
}
for (int i = 0; i < 10; i++) {
    p.getWriteMethod().invoke(newvalue);
}

Say the above code snippet is applied to a bean with a setFoo(Integer) method, and newvalue=3. Then the code works as expected. But if the method signature is setFoo(int) then it does not. Of course you cannot call Method.invoke(...) on the primitive int directly, so you have to work with the wrapper.

Now, Class.cast's Javadoc does not specify its behavior on primitive types. It seems to just implement the typecheck by using Class.isInstance, which does specify that for primitive types the return value is always false. I find that equally counterintuitive, but at least isInstance's behavior is documented (and I guess impossible to change now).

Please either fix Class.cast to behave transparently w.r.t. autoboxing, or document its current behavior. The latter would be more palatable if there were some method in Class:

public Class<T> box() {
    if (this == Integer.TYPE) {
        return Integer.class;
    } else if (...others...) {
    } else if (this == Void.TYPE) {
        return this; // ?
    } else {
        assert !isPrimitive();
        return this;
    }
}

Then you could call

c.box().cast(o);

or

if c.box().isInstance(o) ...

which would be fine. Obviously for symmetry a public Class<T> unbox() method would be nice.

Not sure about Void.TYPE; my intuition would be that isInstance would always be false, and cast would succeed only for null.

Comments
EVALUATION Should consider consistency of this fix with that of 6409411.
09-08-2006