[type-annos-observers] Fw: Constraining type annotations to occur just before type

Alex Buckley alex.buckley at oracle.com
Mon Apr 8 14:35:23 PDT 2013


On 4/5/2013 8:13 PM, Srikanth S Adayapalam wrote:
> From:	Markus Keller/Zurich/IBM at IBMCH
> To:	Srikanth S Adayapalam/India/IBM at IBMIN@IBMDE,
> Date:	04/05/2013 10:11 PM
> Subject:	Re: Fw: Constraining type annotations to occur just before type
>
>
> Let's closely look at "@NonNull final String[] s3" again.
>
> I agree that adding TYPE_USE to an existing NonNull's @Target doesn't
> change the code generation for declaration targets like FIELD, and that
> it's not a source-incompatible change from a Java language point of view
> that doesn't attach any semantics to annotations nor to the @Target
> meta-annotation.

Right.

> The declaration annotation will still be compiled into the field_info's
> attributes list. From a language model point of view, the annotation
> belongs to the declaration. If it was actually meant to be a type-use
> annotation, then the tooling that knows about the semantics of the
> annotation would consider the annotation to be on the type of the field,
> i.e. on "String[]".

The annotation is compiled as if a declaration annotation and a type 
annotation. The language model API has been upgraded in concert. It 
exposes @NonNull on the declaration of the field 
(Element#getAnnotationMirrors) and on the type of the field 
(Element#asType#getAnnotationMirrors). The core reflection API has been 
upgraded too.

> On the other hand, the 308 spec says how a type-use annotation is to be
> interpreted: as an annotation on "String", not on "String[]".

First, it is quite possible that @NonNull was intended to apply to 
String and not String[].

Second, even if @NonNull was intended to apply to String[], all that 
means is that client code which uses new methods in the SE 8 API to read 
type annotations will have to be careful if the type annotation is also 
a declaration annotation. Migration isn't always free.

> As the JSR 308 spec says at the end of section 2, we don't expect any real
> use case where an annotation type supports both a declaration and a
> type-use target. This combination just doesn't make sense, since it would
> be unclear which attachment point "wins". They can't both be correct at the
> same time. If a type-use annotation should target the whole field type
> "String[]", then it needs to be put in front of the "[]", i.e. "String
> @NonNull[]".

Sigh. This is the danger of non-normative text in a specification: it 
doesn't take care to spell out the whole story. The use case where both 
are correct is migration from declaration annotations to type annotations.

> Since adding TYPE_USE changes the attachment point of an annotation, this
> is not a compatible change.

Incorrect. Adding TYPE_USE augments the attachment points. The old 
attachment points are still exposed by the SE 7-era API. It is a source, 
binary, and behaviorally compatible change.

> TYPE_USE fundamentally changes the semantics of
> an annotation type and the correct syntax for annotations of that
> annotation type. The jsr308 grammar is not trivial to understand because a
> type-use annotation has the same syntax as a declaration annotation. Just
> consider for a moment, how it would look like if type-use annotations had
> to be written with two @, i.e. "final String @@NonNull[] s3". That makes it
> much easier to keep the different kinds of annotations apart. In the
> grammar, that would clearly separate the two kinds:
>
> TypeUseAnnotations:
>      TypeUseAnnotation
>      TypeUseAnnotations TypeUseAnnotation
>
> TypeUseAnnotation:
>      @Annotation
>
> Type:
>      [TypeUseAnnotations] BasicType {[TypeUseAnnotations] []}
>      [TypeUseAnnotations] ReferenceType {[TypeAnnotations] []}
>
> ReferenceType:
>      Identifier [TypeArguments] { . [TypeUseAnnotations] Identifier
> [TypeArguments]}
>
> // no need for an UnannType, etc.
>
> I'm not actually proposing the @@ syntax, and I don't know if changing the
> grammar like this would make it easier or harder for parser implementers.
> But this would make it clear where a type-use annotation belongs and where
> not.
>
> Adding TYPE_USE to an existing annotation type is similar in impact as
> changing the superclass of a public class. For client code, this can be a
> source-compatible change in some cases, but a breaking change in others.

We're going round in circles. There is no comparison from a Java 
compiler's point of view. Adding TYPE_USE as a target introduces no 
compile-time errors. Client code which seeks to work with both 
declaration and type annotations lives in a different universe and must 
take care.

>> - If TYPE_USE is made the _sole_ target for an annotation type, then the
>> constraint causes the re-targeting to be a source-incompatible change.
>> This is potentially a big problem because the incompatibilities could be
>> anywhere. (Fixing up one annotation processor to look in the new
>> locations is easy by comparison.)
>
> Adding TYPE_USE is _always_ a big problem. Not so much for an annotation
> processor, but for client code where this changes the semantics. I would
> expect that a Java compiler informs me about fallout from that problem,
> rather than trying to hide the difficulties. Java is not a language that
> accepts "minor syntax errors".

I don't understand what this "client code" is. The only place where 
"semantics" is a valid concern is if code starts to use SE 8 API methods 
to read type annotations, since they will appear on the ground type 
(String) which may not have been the intended location (String[]) circa 
SE 7.

Alex


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