Question

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()?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top