RFR: JDK-8267936: PreserveAllAnnotations option isn't tested

Peter Levart plevart at openjdk.java.net
Thu Jun 3 08:52:42 UTC 2021


On Thu, 3 Jun 2021 07:31:14 GMT, David Holmes <david.holmes at oracle.com> wrote:

> > > The code is confusing because it gives no indication that it is aware
> > > that runtime invisible annotations could be present:
> > > /**
> > > * Parses the annotations described by the specified byte array.
> > > * resolving constant references in the specified constant pool.
> > > * The array must contain an array of annotations as described
> > > * in the RuntimeVisibleAnnotations_attribute:
> > > but at the same time it checks for the RUNTIME retention, which means it
> > > must have recognised the possibility there could be something else
> > > there.
> > 
> > 
> > Yes, there could be a CLASS retention annotation there (even though `-XX+PreserveAllAnnotations` was not used at runtime, so rawAnnotations contains the content of `RuntimeVisibleAnnotations` only). Again, such annotation was RUNTIME retention when its use was compiled into a class, but at runtime such annotation may be updated to have CLASS or even SOURCE retention. Such annotation use is filtered out.
> 
> Sorry Peter I'm not following you. I am only talking about runtime here.
> The VM loads a class at runtime and examines the annotation attributes
> that exist in that classfile.

Right, but into which annotation attribute (`RuntimeVisibleAnnotations` vs. `RuntimeInvisibleAnnotations`) of that class the annotation use was encoded depends on what retention the annotation had at compile time, because those attributes are created by `javac` compiler.

> Some will be visible annotations (which
> implies RUNTIME retention), others may be invisible (which implies
> !RUNTIME which I assume means CLASS). It provides access to these via
> the "raw annotations" and the reflection code then processes that
> through the AnnotationProcessor.

Right, so reflection code at runtime accesses the annotations that were compiled into the class annotation attributes by parsing them and filtering out all but RUNTIME annotations. But this filtering is done at runtime and uses annotation's current set of meta-annotations values (i.e. `@Retention`) which can differ from what this same annotation had at class compile time. So this is how current RUNTIME annotations can end up in the `RuntimeInvisibleAnnotations` class attribute and how current CLASS annotations can end up in `RuntimeVisibleAnnotations` class attribute. It's the consequence of separate compilation. 

> 
> I don't know exactly what you mean by an annotation use being compiled
> into a class, but I assume it is something like the way compile-time
> constants are compiled in. But I don't see how that relates to the
> current discussion.

An annotation use is the use of annotation in the source code to annotate something (Class, Method, Field, ...). For example:


@AnnA
public class Use { ... }


`javac` decides into which class attribute (`RuntimeVisibleAnnotations` vs. `RuntimeInvisibleAnnotations`) of Use.class file it will encode the `@AnnA` use by examining `AnnA`'s `@Retention` meta-annotation at that time. Say that at that time the annotation was this:


@Retention(CLASS)
public @interface AnnA {}


`javac` would encode the `Use`'s use of that annotation into the `RuntimeInvisibleAnnotations` attribute of `Use.class`.


Now comes runtime. Annotation maintainer decides to lift the retention of `AnnA` annotation to RUNTIME and now it looks like this:


@Retention(RUNTIME)
public @interface AnnA {}


He tries to run some new code to extract the annotation value from `Use` class at runtime via reflection, because now at runtime the annotation is updated to have RUNTIME retention. But he also doesn't have access to `Use.java` to recompile it with updated annotation. He just has access to `Use.class` that was compiled with an old version of the same annotation. As we said, `Use.class` has encoded the annotation use in its `RuntimeInvisibleAnnotations` attribute. Voila, here comes `-XX+PreserveAllAnnotations` option to enable passing `RuntimeInvisibleAnnotations` attribute with encoded annotations to the reflection runtime and annotation parser which would return such annotation use.

Now imagine whole libraries with classes that use an annotation which began its life as CLASS annotation because it was paired with AnnotationProcessor(s) that processed those annotation uses at compile time, but now some runtime tool emerges that would like to see those annotations too. The maintainer accepts the proposal to promote annotation's retention from CLASS to RUNTIME in new version of annotation. But who is going to re-compile all those libraries?
> 
> David

Regards, Peter

-------------

PR: https://git.openjdk.java.net/jdk/pull/4280


More information about the core-libs-dev mailing list