Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying generic collection type param at runtime (Java Reflection)

I'd like to get the generic type of a collection, using reflection, at runtime.

Code (JAVA):

Field collectionObject = object.getClass().getDeclaredField(
    collectionField.getName());
//here I compare to see if a collection
if (Collection.class.isAssignableFrom(collectionObject.getType())) {
   // here I have to use the generic type of the collection 
   // to see if it's from a specific type - in this case Persistable
   if (Persistable.class.isAssignableFrom(GENERIC_TYPE_COLLECTION.class)) {
   }
}

Is there a way of getting the generic type of the collection in java at runtime? In my case I need the .class of the collection's generic type.

Thanks in advance!

like image 384
gege Avatar asked Jul 14 '09 20:07

gege


People also ask

How do I restrict a generic type in Java?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class.

How do you provide a generic parameterized type?

In order to use a generic type we must provide one type argument per type parameter that was declared for the generic type. The type argument list is a comma separated list that is delimited by angle brackets and follows the type name. The result is a so-called parameterized type.

What is a generic type parameter in Java?

A type parameter, also known as a type variable, is an identifier that specifies a generic type name. The type parameters can be used to declare the return type and act as placeholders for the types of the arguments passed to the generic method, which are known as actual type arguments.

Which one of the following options is the correct name for empty type parameter?

It is called generics.


1 Answers

Type erasure means that information about the generic type of an object simply isn't present at execution time.

(The link is to the relevant section of Angelika Langer's Java Generics FAQ which should answer virtually every question you could possibly ask about Java generics :)

However, you're not really interested in the type of an object - you're interested in the type of a field. I misread the question, and although the answer has been accepted I hope to make amends by fixing it now :)

If the field doesn't use a type parameter itself, it can be done. For example:

import java.lang.reflect.*;
import java.util.*;

public class Test
{
    public List<String> names;

    public static void main(String [] args)
        throws Exception // Just for simplicity!
    {
        Field field = Test.class.getDeclaredField("names");

        ParameterizedType type = (ParameterizedType) field.getGenericType();

        // List
        System.out.println(type.getRawType());

        // Just String in this case
        for (Type typeArgument : type.getActualTypeArguments())
        {
            System.out.println("  " + typeArgument);
        }
    }
}

If the field were in a class T with the field being List<T> then you'd have to know the type argument for the instance in order to know the type argument for the collection.

Translating this into your required code is somewhat tricky though - you really need to know the type argument at the point of the collection class. For instance, if someone declared:

public class StringCollection implements Collection<String>

and then had a field of type StringCollection, that field itself wouldn't have any type arguments. You'd then need to check getGenericSuperType and getGenericInterfaces recursively until you found what you wanted.

It's really not going to be easy to do that, even though it's possible. If I were you I'd try to change your design so that you don't need this.

like image 144
Jon Skeet Avatar answered Oct 27 '22 10:10

Jon Skeet