Simple way to get wrapper class type in Java

Viewed 25774

I have a piece of code where I need to pass the class of a field in a method. Because of the mechanics of my code I can only handle reference objects and not primitives. I want an easy way of determining if a Field's type is primitive and swap it with the appropriate wrapper class. So in code what I do so far is something like this:

Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType();
if (c == int.class) {
    c = Integer.class;
}
else if (c == float.class) {
    c = Float.class;
}
// etc
myMethod(c);

This works fine, except for the fact that I need to explicitly check for all the primitive types and swap them with the appropriate wrapper class. Now I know that there are not so many primitive types and it won't be a problem to simply list them all, but I was wondering if there was an easier and more elegant way of doing it.

8 Answers
Class<?> toWrapper(Class<?> clazz) {
    if (!clazz.isPrimitive())
        return clazz;

    if (clazz == Integer.TYPE)
        return Integer.class;
    if (clazz == Long.TYPE)
        return Long.class;
    if (clazz == Boolean.TYPE)
        return Boolean.class;
    if (clazz == Byte.TYPE)
        return Byte.class;
    if (clazz == Character.TYPE)
        return Character.class;
    if (clazz == Float.TYPE)
        return Float.class;
    if (clazz == Double.TYPE)
        return Double.class;
    if (clazz == Short.TYPE)
        return Short.class;
    if (clazz == Void.TYPE)
        return Void.class;

    return clazz;
}

So you want to get the wrapper class type, ok.

No need to query the types or reference look up tables because java already does it anyway. Let's walk through the problem together...

Synopsis

We are retrieving a field and then find it contains a primitive type.

Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType(); // Gets the declared primitive type

But instead we want the wrapper type.

Primitive types in Java

Now as you already found out the only thing a primitive class is good for is to return true for c.isPrimitive();.

From wiki books - java programming:

Primitive types are the most basic data types available within the Java language. There are 8: boolean , byte , char , short , int , long , float and double . These types serve as the building blocks of data manipulation in Java. Such types serve only one purpose — containing pure, simple values of a kind.

So why do we want to know the wrapper type?

Attempting to use primitives in any other way and you are in for a lot of hurt.

Cannot make a new instance of a primitive.

Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.newInstance();
//  java.lang.InstantiationException thrown: int
//        at Class.newInstance (Class.java:545) 

Cannot cast to a primitive type.

Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(0);
//  java.lang.ClassCastException thrown: Cannot cast java.lang.Integer to int
//        at Class.cast (Class.java:3578)

Can cast to a null wrapper type. Yeah! \o/

Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(null);

No exceptions and the variable wrapper is of type class java.lang.Integer but with a value of null, a whole lot of good that will do us.

Primitives are not even inherited from wrappers.

boolean isSuperClass = Integer.class.isAssignableFrom(int.class); // false

This is obviously not getting us anywhere so lets rather take a step back from the problem and have a look at the bigger picture.

When at first you don't succeed...

Lets recap: We are retrieving a field which has to come from somewhere so if we were to fill in the gaps left out in the question it might look something like this.

public class Simple {
    public static int field;
    
    public static Field getTheField() {
        return Simple.class.getField("field"); // Actual method that returns our Field
    }

    public static void main(String[] args) {
        Field f = getTheField();
        Class<?> c = f.getType();
    }
}

Instead of fighting against the machine lets rather work with it. One of the perks of primitives are that they will initialise to a default value 0 instead of null. Lets see if we can use that.

Get wrapper class from wrapped instance.

public class Simple {
    public static int field;

    public static Field getTheField() {
        return Simple.class.getField("field"); // Actual method that returns our Field
    }

    public static void main(String[] args) {
        Field f = getTheField();
        Object wrapped = f.get(null);    // Integer value 0
        Class<?> c = wrapped.getClass(); // class java.lang.Integer
    }
}

That was much easier than before and we didn't even have to do anything, auto boxing, everything was done for us. Yet another perk for not trying to go against the stream.

Lets improve on that, refactor and make it a little more reusable by extracting a method.

Implement a manual boxing method.

We can do the same auto boxing with generics:

public class Simple {
    public static int field;

    public static Field getTheField() {
        return Simple.class.getField("field"); // Actual method that returns our Field
    }

    public static <T> T wrap(T t) {
        return t;
    }

    public static void main(String[] args) {
        Field f = getTheField();
        Class<?> c = Simple.wrap(f.get(null)).getClass(); // class java.lang.Integer
    }
}

A simple primitive wrap without ever having to look at the types or use look up tables because java already does it anyway.

Conclusion

The simple solution using pure java to get the wrapper class from a primitive field:

Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.get(null).getClass(); 

Or you can replace null with an instance if the field is not static.

nJoy!

With a more recent jdk, this is a one-liner now:

@SuppressWarnings("unchecked")
public static <T> Class<T> wrap(Class<T> c) {
    return (Class<T>) MethodType.methodType(c).wrap().returnType();
}

@SuppressWarnings("unchecked")
public static <T> Class<T> unwrap(Class<T> c) {
    return (Class<T>) MethodType.methodType(c).unwrap().returnType();
}

Here is a test that I wrote using JMH and here are the results:

Benchmark                        Mode  Cnt   Score   Error  Units
PrimitiveToWrapper.ifStatements  avgt   30  42.112 ± 0.716  ns/op
PrimitiveToWrapper.map           avgt   30  45.018 ± 0.923  ns/op
PrimitiveToWrapper.wrap          avgt   30  52.369 ± 0.836  ns/op

The difference is rather small.

Related