[type-annos-observers] @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-observers
mailing list