Java: Runtime reflection in compilation phase (?!)

Viewed 59

In Element#getAnnotation(Class<A> annotationType) javadoc it is stated that

Note: This method is unlike others in this and related interfaces. It operates on runtime reflective information — representations of annotation types currently loaded into the VM — rather than on the representations defined by and used throughout these interfaces. Consequently, calling methods on the returned annotation object can throw many of the exceptions that can be thrown when calling methods on an annotation object returned by core reflection. This method is intended for callers that are written to operate on a known, fixed set of annotation types.

Yet, this method is frequently used in annotation processing which is part of the compilation phase. What I want to understand is what, how, and why things gets loaded to VM at compilation time, and what are the pros and cons.

For example, in the case of Element#getAnnotation(Class<A> annotationType), is there any drawbacks (except possibly not being able to access values of type class in the annotation), compared to if we get the same information using mirrors (which is usually the longer code)?

1 Answers

The javac compiler is expected to be a JVM application (if only because javax.lang.model is a Java-based API). So it can naturally use runtime Reflection during it's execution.

What the documentation tries to say, — a bit clumsily perhaps, — is that JVM compiler isn't expected to load the classes it builds from source code (or their binary compilation dependencies). But when you use Element#getAnnotation(Class<A> annotationType), it might have to.

The documentation you cited actually lists several Exception classes, that may be thrown due to this:

  1. MirroredTypeException. As you already realized, it is thrown when you try to load a type that hasn't been built yet, used as argument within an annotation.
  2. AnnotationTypeMismatchException, EnumConstantNotPresentException and IncompleteAnnotationException. Those exceptions can be thrown when the version of annotation loaded by javac does not match the version, referenced by build classpath

The mismatched versions can be hard to avoid, because some build systems, such as Gradle, require you to specify annotation processor separately from the rest of dependencies.

Related