RFR: 8231436: Fix the applicability of a no- at Target annotation type

Alex Buckley alex.buckley at oracle.com
Fri Feb 5 20:14:48 UTC 2021

On 2/5/2021 6:44 AM, Joel Borggren-Franck wrote:
> In isolation yes, “all contexts” makes sense, but so does “all
> declaration contexts”. What worries me here is that we change the
> semantics of programs written as far back as 2004. While I don’t
> think this is an absolute no, we shouldn’t do this lightly, the gain
> should be substantial, and the risk well quantified. One aspect here
> is that while annotation interface declarations without @Target might
> very well be poorly written, it is/was still the only way to specify
> "all current and future declaration targets”, it is/was also the only
> alternative with some brevity to specify all current declaration
> contexts, the alternative being to type out 9 ElementTypes.

The original meaning of no- at Target in 2004 was open-ended, the "all 
contexts" of its day -- "If a Target meta-annotation is not present on 
an annotation type declaration, the declared type may be used on any 
program element."

When Java 8 added annotations on declarations of type parameters (a 
declaration context overlooked by Java 5, and addressed by JSR 308), we 
should arguably have thrown that new declaration context into the "all 
contexts" pot from Java 5 and leveraged Java 8's richer terminology to 
state the meaning of no- at Target as "all declaration contexts". We didn't 
do that out of an abundance of caution, not wanting to change the 
semantics of programs written back to 2004. Instead, we gave what I now 
regard as undue weight to what was important in 2012: Java 7's 
locations, a.k.a. Java 5's locations. This led to a weird 
backward-looking policy that does poorly when new declaration contexts 

I think your dislike of no- at Target meaning "all contexts" is not that it 
includes type contexts as such, but rather that when it meets the corner 
case of ambiguous locations, it causes some annotations to be written 
into the class file twice. If the corner case somehow didn't exist, I 
think you would appreciate the brevity of being able to get all 
declaration contexts without spelling out nine targets, and you just 
wouldn't think about the type contexts coming along for the ride.

The corner case is a fact of Java life (and I might even concede it's 
larger than a corner case, given the prominence of the ambiguous 
locations), but I don't want it to dominate the decision about the 
meaning of no- at Target. The simplicity of "all contexts" was appealing in 
2004 and it's appealing in 2021. The cost of carelessly omitting @Target 
was _always_ that an annotation processor might see @Foo in locations it 
didn't expect as Java evolved, and now there may be some class file 
overhead too. The power to avoid surprises is entirely in the hands of 
Foo's owner -- they're declaring what looks like an API but is really a 
new modifier for Java programs, so they ought to be concerned with how 
their annotations affect user code.

Encouraging the owner to specify @Target by offering an 
ElementType.DECLARATIONS constant that means "all [current and future] 
declaration contexts" is a good idea, balancing how ElementType.TYPE_USE 
means "all [current and future] type contexts".

(In Java 15, TYPE_USE implied 16 type contexts; in Java 16, TYPE_USE 
implies 17 type contexts, the addition being the type in a record 
component declaration. Open-ended rules work! They embody "lumping, not 


> An alternative would be to adopt your original proposal, “all current
> and future declaration contexts”, and adding an ElementType
> corresponding to this default. This way the question “where are
> annotations applicable?” would be solved, the user can easily and
> with brevity opt in to all contexts by using something like
> “@Target({DECLARATIONS, TYPE_USE})" and the backward compatibility
> risk is lower. The downside is It would mean more work for us in
> implementing this.
> cheers /Joel

More information about the compiler-dev mailing list