0

Consider:

  @Retention(RetentionPolicy.RUNTIME)
  @Target({ ElementType.TYPE_USE })
  @interface A {}

  @A
  final class B {}

This compiles.

How, either using java.lang.reflect.* constructs or javax.lang.model.* constructs, do I read @A?

A commenter didn't understand what I meant by "read". Here is what I mean.

Using reflection as an example, cls.getAnnotations() will, unexpectedly, return a collection featuring @A (incorrectly) as a declaration annotation, because it returns declaration annotations (@A is not listed as being able to be applied to ElementType.TYPE, but that's where it "shows up" here). Type annotations are returned by AnnotatedType implementations. But I see no way to get an AnnotatedType for a Class.

That's fine; sometimes reflection doesn't give you everything (I've been told elsewhere). But using javax.lang.model.* classes, I can't get this annotation either. I would expect it to appear in:

elements.getTypeElement("B").asType().getAnnotationMirrors();

…but that List is empty. (This might be due to https://bugs.openjdk.org/browse/JDK-8225377.)

In case it matters, when looking at the actual .class file, I see no occurrence of the string RuntimeVisibleTypeAnnotations, suggesting that @A is not, in fact, actually recorded or retained as a type use annotation in the .class file. I also see RuntimeVisibleAnnotations and @A appears after it, so it would seem that this annotation is incorrectly recorded as a declaration/element annotation. I will probably file another JDK bug.

I'm also initiating a discussion on compiler-dev: https://mail.openjdk.org/pipermail/compiler-dev/2023-February/022184.html

Laird Nelson
  • 15,321
  • 19
  • 73
  • 127
  • I would like to help you, but I don't understand your question. Will you please explain further about what you want to know? Take a minute to check out [ask] for some tips on improving your quesiton. – Code-Apprentice Feb 16 '23 at 19:46
  • When you say "Read @A", do you mean testing for the presence of `@A` on some target, or finding the value of an applied annotation? The former seems like what you want, since you didn't specify any values for that annotation, but wanted to be sure. – Rogue Feb 16 '23 at 19:50

2 Answers2

0

Since you're using Reflection to access Runtime information - it's obvious that Retention Policy will always be RUNTIME. Otherwise Annotation metadata will not be available at Runtime. Just a reminder.

Next snippet should give you an information about Annotation metadata you are looking for at Runtime.

B  bInstance = new B();

A desiredAnnotation = bInstance.getClass().getAnnotation(A.class);

if (desiredAnnotation != null) {
    System.out.println("Annotation Target - Element Type: " + Arrays.toString(desiredAnnotation.annotationType().getAnnotation(Target.class).value()));
    System.out.println("Retention Policy:  " + desiredAnnotation.annotationType().getAnnotation(Retention.class).value());
}
Ryan M
  • 18,333
  • 31
  • 67
  • 74
0

This appears to be a misreading on my part of the Java Language Specification. To paraphrase, while a TYPE_USE annotation may annotate type contexts enumerated in §4.11, that is not all that it can annotate.

It is also a declaration annotation when applied to class or interface or type parameter declarations, as explained in section 9.7.4 (and as Bill Mair correctly noted in a now-deleted answer):

"A declaration annotation is an annotation that applies to a declaration, and whose annotation interface is applicable in the declaration context (§9.6.4.1) represented by that declaration; or an annotation that applies to a class, interface, or type parameter declaration, and whose annotation interface is applicable in type contexts (§4.11).")

So in fact @A in my example is both a declaration annotation and a type annotation. It should, and does, appear in the array of declaration annotations returned by Class#getAnnotations(), even though it is annotated only with ElementType.TYPE_USE.

It would seem, therefore, that an annotation annotated with

@Target({ ElementType.TYPE_USE })

…behaves exactly as if it were annotated with:

@Target({ ElementType.TYPE, ElementType.TYPE_PARAMETER, ElementType.TYPE_USE })
Laird Nelson
  • 15,321
  • 19
  • 73
  • 127