Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get generic type information from getAnnotatedParameterTypes() in Java 8?

It seems like getAnnotatedParameterTypes() returns an array of AnnotatedTypes holding raw, rather than generic, types. For example:

public <T> void genericMethod(T t) {
}

@Test
public void testAnnotatedTypes() throws ReflectiveOperationException {
    Method method = getClass().getMethod("genericMethod", Object.class);

    Type type = method.getGenericParameterTypes()[0];
    assertTrue(type instanceof TypeVariable);

    AnnotatedType annotatedType = method.getAnnotatedParameterTypes()[0];

    // This fails; annotatedType implements only AnnotatedType
    assertTrue(annotatedType instanceof AnnotatedTypeVariable);

    // This fails too; type is a TypeVariable while annotatedType.getType() is
    // Object.class
    assertEquals(type, annotatedType.getType());
}

What's the reason for the disagreement with getGenericParameterTypes()?

like image 256
Tavian Barnes Avatar asked Apr 12 '14 02:04

Tavian Barnes


People also ask

How do you find the type of generic class?

You can get around the superfluous reference by providing a generic static factory method. Something like public static <T> GenericClass<T> of(Class<T> type) {...} and then call it as such: GenericClass<String> var = GenericClass. of(String. class) .

How do I get a class instance of generic type T?

The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. A solution to this is to pass the Class of the type parameter into the constructor of the generic type, e.g.

How do you define a generic class in Java?

A Generic class simply means that the items or functions in that class can be generalized with the parameter(example T) to specify that we can add any type as a parameter in place of T like Integer, Character, String, Double or any other user-defined type.


1 Answers

There's a bug report about this, and it has since been fixed.

There's a difference between Method#getGenericParameterTypes() and Method#getAnnotatedParameterTypes().

The former makes guarantees about the types it returns

If a formal parameter type is a parameterized type, the Type object returned for it must accurately reflect the actual type parameters used in the source code.

If a formal parameter type is a type variable or a parameterized type, it is created. Otherwise, it is resolved.

while the latter doesn't, not clearly at least:

Returns an array of AnnotatedType objects that represent the use of types to specify formal parameter types of the method/constructor represented by this Executable.

We have to assume that getAnnotatedParameterTypes() returns the erased types (although it may not have been intended that way). The unbounded type variable T is erased to Object. If you had <T extends Foo>, it would be erased to Foo.

As for the comments, about getting the annotation from a type argument in a method parameter, there's no way given the above. One would think it works as it does for fields.

public static void main(String[] args) throws Exception {
    Field field = Example.class.getField("field");
    AnnotatedParameterizedType annotatedParameterizedType = (AnnotatedParameterizedType) field
            .getAnnotatedType();

    System.out.println(annotatedParameterizedType
            .getAnnotatedActualTypeArguments()[0].getType());
    System.out.println(Arrays.toString(annotatedParameterizedType
            .getAnnotatedActualTypeArguments()[0].getAnnotations()));
}

@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.TYPE_USE })
@interface Bar {
}

public List<@Bar String> field;

which prints

class java.lang.String
[@com.example.Example$Bar()]

I very much think it's a bug that needs fixing and will be following the bug report linked above.

like image 118
Sotirios Delimanolis Avatar answered Sep 20 '22 11:09

Sotirios Delimanolis