@Target mixing TYPE_USE and declaration annotation

Markus Keller markus_keller at ch.ibm.com
Tue Oct 22 11:04:50 PDT 2013


To finish the series of mails lost in the maligned observers list, I want 
to mention
http://mail.openjdk.java.net/pipermail/type-annotations-spec-observers/2013-April/000152.html

The gist is that allowing @Target annotations with a mixture of TYPE_USE 
and declaration elements is not only bad for implementers of annotation 
processors, but also for users of such annotations. I'm still convinced 
that mixing TYPE_USE with other targets should be forbidden.

Page 20 of 308-20131016.pdf has such an example:
> -------
If TA is additionally meta-annotated with @Target(ElementType.FIELD), then 
the term
@TA java.lang.Object is legal in locations which are both declaration and 
type contexts,
such as a field declaration @TA java.lang.Object f;. Here, @TA is deemed 
to apply
to the declaration of f (and not to the type java.lang.Object) because TA 
is applicable
in the field declaration context.
> -------

Because an annotation can only have a single @Target annotation, the 
beginning would better be written as: "If TA is meta-annotated with 
@Target({ElementType.TYPE_USE, ElementType.FIELD}), ...".

And the example hides the even worse ramifications for array-typed fields:

@TA Object[] f2;

The SE 7 APIs consider @TA an annotation on field f2.
The SE 8 APIs consider @TA also a type annotation on Object (not on the 
field type Object[]!).

Now what does that mean e.g. for "@Nullable Object[] f2;"? If an 
annotation processor wants to be source-compatible with SE 7 code, then it 
cannot rely on the SE 8 meaning of such a mixed-target annotation! 
Although the 308 spec attaches the type annotation to the type "Object", 
the annotation processor still has to adhere to the legacy meaning and 
must attach it to "Object[]". I.e. it effectively *cannot* make use of the 
added TYPE_USE element type in this case.

If an annotation provider doesn't care about these corner cases with 
qualified and array types, then he can just switch to @Target(TYPE_USE). 
Otherwise, he should deprecate the old declaration annotation and declare 
a new type annotation.

The current JSR 308 proposal doesn't tell that mixing target elements is 
considered bad style nor that it is discouraged.

http://types.cs.washington.edu/jsr308/specification/java-annotation-design.html 
says:
> Note from the above examples that a programmer is permitted to write can 
write a @Target meta-annotation indicating that an annotation, such as 
@FTAnno or @MTAnno, is both a type annotation and a declaration 
annotation. We have not found an example where such a meta-annotation is 
desirable for a newly-created annotation; although it is legal, it is 
considered bad style. By contrast, when migrating from Java SE 7 and older 
annotation processors to Java SE 8 and newer annotation processors, it may 
be desirable for the annotation to be both a type annotation and a 
declaration annotation, for reasons of backward compatibility.

The last sentence about migration was only added in the very last 
revision, and it gives a very bad advice that locks annotation providers 
and users into an eternal backwards-compatibility mode.

Summary: The spec allows a bad style for compatibility reasons, but it 
effectively fails to deliver that promise. Backwards compatibility and 
correct treatment of TYPE_USE exclude each other, and the spec should not 
make it appear like there is a solution.

If it's too late for this change, then the spec should at least tell that 
mixed-target annotation types are dangerous and discouraged.

Markus



More information about the type-annotations-spec-comments mailing list