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

3
  • This is also true for ParameterizedTypes. As far as I can tell, there's no way to get the annotation for List<@SomeAnnotation T> because of the same problem. Weird! Commented Apr 12, 2014 at 3:45
  • Oh wow, I hadn't even gotten that far yet. That's horrible! Commented Apr 12, 2014 at 14:16
  • @Jeffrey Thanks for putting a bounty on this, I was just about to. Commented Apr 14, 2014 at 15:38

1 Answer 1

7
+50

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Good find with the bug report. +1
Looks like the bug is fixed in HEAD, simple one-line change. hg.openjdk.java.net/jdk9/dev/jdk/rev/a4138f3a3432

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.