Dynamically find the class that represents a primitive Java type
Asked Answered
A

8

54

I need to make some reflective method calls in Java. Those calls will include methods that have arguments that are primitive types (int, double, etc.). The way to specify such types when looking up the method reflectively is int.class, double.class, etc.

The challenge is that I am accepting input from an outside source that will specify the types dynamically. Therefore, I need to come up with these Class references dynamically as well. Imagine a delimited file a list of method names with lists of parameter types:

doSomething int double
doSomethingElse java.lang.String boolean

If the input was something like java.lang.String, I know I could use Class.forName("java.lang.String") to that Class instance back. Is there any way to use that method, or another, to get the primitive type Classes back?

Edit: Thanks to all the respondents. It seems clear that there is no built-in way to cleanly do what I want, so I will settle for reusing the ClassUtils class from the Spring framework. It seems to contain a replacement for Class.forName() that will work with my requirements.

Acclimate answered 7/10, 2008 at 19:54 Comment(0)
E
22

The Spring framework contains a utility class ClassUtils which contains the static method forName. This method can be used for the exact purpose you described.

In case you don’t like to have a dependency on Spring: the source code of the method can be found e. g. here on their public repository. The class source code is licensed under the Apache 2.0 model.

Note however that the algorithm uses a hard-coded map of primitive types.


Edit: Thanks to commenters Dávid Horváth and Patrick for pointing out the broken link.

Eyeopener answered 7/10, 2008 at 20:12 Comment(2)
The source for the ClassUtils.java file seems to be broken at that link. This one looks up, to meAdp
@Patrick: Sadly, your link has became broken too. However, Spring framework is now available on GitHub. github.com/spring-projects/spring-framework/blob/master/…Kerosene
R
31

The Class instances for the primitive types are obtainable as you said using e.g. int.class, but it is also possible to get the same values using something like Integer.TYPE. Each primitive wrapper class contains a static field, TYPE, which has the corresponding primitive class instance.

You cannot obtain the primitive class via forName, but you can get it from a class which is readily available. If you absolutely must use reflection, you can try something like this:

Class clazz = Class.forName("java.lang.Integer");
Class intClass = clazz.getField("TYPE").get(null);

intClass.equals(int.class);         // => true
Retinoscope answered 7/10, 2008 at 20:2 Comment(4)
This is true, and I was not aware of it. However, in my situation, I need a way of specifying any method can be called reflectively. Therefore, if I accept java.lang.Integer to represent int values, I'll lose the ability to call methods that accept Integer values.Acclimate
You can just test to see if you have received some arbitrary special type (say: "int") and then do the rewrite appropriately. There is no string value that you can feed to forName that will retrieve the class of a primitive type.Retinoscope
Instead you can just do Integer.TYPEEuphrasy
@RagunathJawahar or just int.class, as already shown in the answer. Which, by the way, gets compiled to Integer.TYPE behind the scenes.Statvolt
E
22

The Spring framework contains a utility class ClassUtils which contains the static method forName. This method can be used for the exact purpose you described.

In case you don’t like to have a dependency on Spring: the source code of the method can be found e. g. here on their public repository. The class source code is licensed under the Apache 2.0 model.

Note however that the algorithm uses a hard-coded map of primitive types.


Edit: Thanks to commenters Dávid Horváth and Patrick for pointing out the broken link.

Eyeopener answered 7/10, 2008 at 20:12 Comment(2)
The source for the ClassUtils.java file seems to be broken at that link. This one looks up, to meAdp
@Patrick: Sadly, your link has became broken too. However, Spring framework is now available on GitHub. github.com/spring-projects/spring-framework/blob/master/…Kerosene
S
20

Probably you just need to map the primitives and for the rest of the classes perform the "forName" method:

I would do something like:

void someWhere(){
     String methodDescription = "doSomething int double java.lang.Integer java.lang.String"
     String [] parts = methodDescription.split();
     String methodName= parts[0]
     Class [] paramsTypes = getParamTypes( parts ); // Well, not all the array, but a, sub array from 1 to arr.length..  

    Method m = someObject.class.getMethod( methodName, paramTypes );
    etc. etc etc.
}

public Class[] paramTypes( String [] array ){
     List<Class> list = new ArrayList<Class>();
     for( String type : array ) {
         if( builtInMap.contains( type )) {
             list.add( builtInMap.get( type ) );
          }else{
             list.add( Class.forName( type ) );
          }
     }
     return list.toArray();
}  

    // That's right.
Map<String,Class> builtInMap = new HashMap<String,Class>();{
       builtInMap.put("int", Integer.TYPE );
       builtInMap.put("long", Long.TYPE );
       builtInMap.put("double", Double.TYPE );
       builtInMap.put("float", Float.TYPE );
       builtInMap.put("bool", Boolean.TYPE );
       builtInMap.put("char", Character.TYPE );
       builtInMap.put("byte", Byte.TYPE );
       builtInMap.put("void", Void.TYPE );
       builtInMap.put("short", Short.TYPE );
}

That is, create a map where the primitives types are stored and if the description belong to a primitive then use the mapped class. This map may also be loaded from an external configuration file, to add flexibility so you add String as a built in instead of java.lang.String or potentially have method like this.

"doSomething string yes|no "

There are lots of this kind of code in OS projects like Struts, Hibernate, Spring and Apache libs ( just to mention a few ) , so you don't need to start from zero.

Systematist answered 7/10, 2008 at 21:18 Comment(3)
This is what is done inside of ObjectInputStream as well, it simply does a forName() lookup and if it throws a ClassNotFoundException, does a map lookup.Murine
Thanks for the reply. I will reuse the utility method in Spring's ClassUtils that uses this lookup process.Acclimate
Where are you using this "low level" code? Take a deep look on how to secure your service, otherwise you might get some "System.exit()" call from your remote client, and believe me the server will shut down!Systematist
K
5

Apache Commons Lang has ClassUtils.getClass(String), which supports primitive types.

Kong answered 25/6, 2013 at 8:6 Comment(2)
Doesn't work for me. I have a Field of type long. Calling ClassUtils.getClass(field.getType().toString()) simply returns long and not java.lang.LongTowroy
@Towroy that’s precisely the purpose of this method. Neither the question nor the answer were about returning the wrapper type.Statvolt
R
3

A number of Class methods don't handle primitives in a consistent fashion unfortunately. A common way around this in forName is to have a table like;

private static final Map<String, Class> BUILT_IN_MAP = 
    new ConcurrentHashMap<String, Class>();

static {
    for (Class c : new Class[]{void.class, boolean.class, byte.class, char.class,  
            short.class, int.class, float.class, double.class, long.class})
        BUILT_IN_MAP.put(c.getName(), c);
}

public static Class forName(String name) throws ClassNotFoundException {
    Class c = BUILT_IN_MAP.get(name);
    if (c == null)
        // assumes you have only one class loader!
        BUILT_IN_MAP.put(name, c = Class.forName(name));
    return c;
}
Rifkin answered 14/3, 2009 at 21:10 Comment(0)
D
2

The following code talks about how to get the class of a primitive type who's field name is known, e.g. in this case 'sampleInt'.

public class CheckPrimitve {
    public static void main(String[] args) {
        Sample s = new Sample();
        try {
            System.out.println(s.getClass().getField("sampleInt").getType() == int.class); // returns true
            System.out.println(s.getClass().getField("sampleInt").getType().isPrimitive()); // returns true
        } catch (NoSuchFieldException e) {          
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }       
    }
}

class Sample {
    public int sampleInt;
    public Sample() {
        sampleInt = 10;
    }
}

One can also check whether a given value is primitive or not by getting it's respective wrapper class or it's field value.

    public class CheckPrimitve {
        public static void main(String[] args) {
            int i = 3;
            Object o = i;
            System.out.println(o.getClass().getSimpleName().equals("Integer")); // returns true
            Field[] fields = o.getClass().getFields();
            for(Field field:fields) {
                System.out.println(field.getType()); // returns {int, int, class java.lang.Class, int}
            }
        }
    }
Decagon answered 1/10, 2012 at 6:26 Comment(1)
Thanks for posting an answer! While a code snippet could answer the question it's still great to add some addition information around, like explain, etc ..Brosy
H
1

Google Guava offers com.google.common.primitives.Primitives for this sort of stuff.

Hinds answered 8/3, 2017 at 14:5 Comment(0)
L
0

You can use this code :)

/**
 * Get an array class of the given class.
 *
 * @param klass to get an array class of
 * @param <C>   the targeted class
 * @return an array class of the given class
 */
public static <C> Class<C[]> arrayClass(Class<C> klass) {
    return (Class<C[]>) Array.newInstance(klass, 0).getClass();
}

/**
 * Get the class that extends {@link Object} that represent the given class.
 *
 * @param klass to get the object class of
 * @return the class that extends Object class and represent the given class
 */
public static Class<?> objectiveClass(Class<?> klass) {
    Class<?> component = klass.getComponentType();
    if (component != null) {
        if (component.isPrimitive() || component.isArray())
            return Reflect.arrayClass(Reflect.objectiveClass(component));
    } else if (klass.isPrimitive()) {
        if (klass == char.class)
            return Character.class;
        if (klass == int.class)
            return Integer.class;
        if (klass == boolean.class)
            return Boolean.class;
        if (klass == byte.class)
            return Byte.class;
        if (klass == double.class)
            return Double.class;
        if (klass == float.class)
            return Float.class;
        if (klass == long.class)
            return Long.class;
        if (klass == short.class)
            return Short.class;
    }

    return klass;
}

/**
 * Get the class that don't extends {@link Object} from the given class.
 *
 * @param klass to get the non-object class of
 * @return the non-object class of the given class
 * @throws IllegalArgumentException when the given class don't have a primitive type
 */
public static Class<?> primitiveClass(Class<?> klass) {
    if (klass == Character.class)
        return char.class;
    if (klass == Integer.class)
        return int.class;
    if (klass == Boolean.class)
        return boolean.class;
    if (klass == Byte.class)
        return byte.class;
    if (klass == Double.class)
        return double.class;
    if (klass == Float.class)
        return float.class;
    if (klass == Long.class)
        return long.class;
    if (klass == Short.class)
        return short.class;

    throw new IllegalArgumentException(klass + " don't have a primitive type");
}
Langsdon answered 25/11, 2019 at 19:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.