JDK-6176992 : (reflect) Add support to java.lang.Class for wrapper type conversions
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 1.1.6,1.3.0,5.0,6
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: generic,solaris_9
  • CPU: generic,sparc
  • Submitted: 2004-10-11
  • Updated: 2013-08-14
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
There is no generic means of getting the wrapper type for a primitive class or the wrapped primitive type for a wrapper class.  I propose adding the following methods to java.lang.Class:

public boolean isWrapper ()
public Class<?> getWrapperType ()
public Class<?> getWrappedType ()

isPrimitiveWrapper would return true for the java.lang types Boolean, Byte, Short, Character, Integer, Long, Float, and Double.  It would return false for all other types.

getWrapperType would return null for all classes except the eight primitive types Boolean.TYPE, Byte.TYPE, Short.TYPE, Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, and Double.TYPE which would return the corresponding java.lang wrapper types Boolean, Byte, Short, Character, Integer, Long, Float, and Double, respectively.

getWrappedType would return null for all classes except the eight java.lang wrapper types Boolean, Byte, Short, Character, Integer, Long, Float, and Double which would return the corresponding primitive types Boolean.TYPE, Byte.TYPE, Short.TYPE, Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, and Double.TYPE, respectively.

Alternative names for the proposed methods are:

public boolean isPrimitiveWrapper ()
public Class<?> getPrimitiveWrapperType ()
public Class<?> getWrappedPrimitiveType ()


JUSTIFICATION :
When using reflection, primitive values for Field values and for Method parameters and return types are wrapped (e.g. calling the invoke method on a java.lang.reflect.Method object for a method with the signature int foo() returns an an Integer object containing the int value).  Certain programming constructs using reflection are inelegant without a means to convert the actual type to the reflected type (see example).

Since the wrapper types are integral to the Java language (even more so with the addition of auto {un}boxing), it is reasonable and useful to provide support for primitive wrapper type conversion as part of the language reflection mechanism.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
// I realize this simple example is not required to check for a Comparable
// Field in the constructor as it can simply throw a ClassCastException
// from compare, but I was trying to keep the example simple.

import java.lang.reflect.Field;
import java.util.Comparator;

public class GenericComparator implements Comparator, java.io.Serializable {
    private final Field field;

    public GenericComparator (Field field) {
        Class type = field.getType();
        if (type.isPrimitive())
            type = type.getWrapper();
        if (!Comparable.class.isAssignableFrom(type))
            throw new IllegalArgumentException("Field type must be Comparable");
        this.field = field;
    }

    public int compare (Object obj1, Object obj2) {
        try {
            Comparable comp1 = (Comparable) field.get(obj1);
            return comp1.compareTo(field.get(obj2));
        }
        catch (IllegalAccessException ex) {
            throw (ClassCastException) new ClassCastException().initCause(ex);
        }
    }
}

ACTUAL -
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.Map;
import java.util.HashMap;

public class GenericComparator implements Comparator, java.io.Serializable {
    private static final Map<Class, Class> WRAPPERS = new HashMap<Class, Class>();

    static {
        WRAPPERS.put(byte.class,    Byte.class);
        WRAPPERS.put(short.class,   Short.class);
        WRAPPERS.put(char.class,    Character.class);
        WRAPPERS.put(int.class,     Integer.class);
        WRAPPERS.put(long.class,    Long.class);
        WRAPPERS.put(float.class,   Float.class);
        WRAPPERS.put(double.class,  Double.class);
        WRAPPERS.put(boolean.class, Boolean.class);
    }

    private final Field field;

    public GenericComparator (Field field) {
        Class type = field.getType();
        if (type.isPrimitive())
            type = WRAPPERS.get(type);
        if (!Comparable.class.isAssignableFrom(type))
            throw new IllegalArgumentException("Field type must be Comparable");
        this.field = field;
    }

    public int compare (Object obj1, Object obj2) {
        try {
            Comparable comp1 = (Comparable) field.get(obj1);
            return comp1.compareTo(field.get(obj2));
        }
        catch (IllegalAccessException ex) {
            throw (ClassCastException) new ClassCastException().initCause(ex);
        }
    }
}


CUSTOMER SUBMITTED WORKAROUND :
The work around is to declare and initialize a HashMap to contain the desired mapping from primitive class to wrapper class and/or from wrapper class to primitive class.
###@###.### 10/11/04 16:43 GMT

Comments
EVALUATION Will consider for Dolphin.
09-08-2006

EVALUATION Contribution-Forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?messageID=12007&forumID=1463
15-03-2006

EVALUATION Under consideration.
02-12-2005