[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