A simpler model for repeating annotations
Remi Forax
forax at univ-mlv.fr
Fri Dec 28 14:45:18 PST 2012
On 12/28/2012 09:17 PM, Alex Buckley wrote:
> Feedback from Java EE architects indicates a strong preference for
> 100% behavioral compatibility for legacy core reflection methods.
>
> Summarizing Mike Keith's comments: 1) getAnnotation(Class) must not
> return one @Foo annotation if multiple @Foo annotations were present
> in source, and 2) getAnnotations() must not return multiple @Foo
> annotations if they present in source.
>
> These requirements imply keeping containment at the heart of
> repeatability. Why? Assume there were no containers, and you could
> simply write:
>
> @Repeatable @interface Foo {}
>
> such that @Foo @Foo on class A is compiled directly into A.class. This
> scheme would impose high complexity on legacy core reflection methods.
> getAnnotation(Foo.class) would have to read _all_ annotations
> (declared and inherited) to detect multiple @Foo annotations then
> return null or throw an exception. (Remember, returning one of the
> multiple annotations is "wrong".) getAnnotations() would have similar
> trouble deciding what to return if multiple @Foo annotations are
> found. In essence, the legacy core reflection methods are morally
> incompatible with uncontained multiple annotations. The solution is to
> compile multiple annotations with containers, and have the legacy core
> reflection methods behave identically to Java SE 7 (no look through).
>
> To support new reflective clients who understand repeating
> annotations, we can keep the previously-proposed getAnnotations(Class)
> which looks through containers. That is, getAnnotations(Foo.class)
> returns @Foo @Foo because it a) detects that Foo.class is a repeatable
> annotation type with a containing annotation type of FooContainer,
> then b) looks through any @FooContainer present.
>
> It is clear that a repeatable annotation type must still nominate its
> containing annotation type, but the reverse is no longer true. That
> is, the declaration of FooContainer no longer needs to say
> @ContainerFor(Foo.class). This is a direct consequence of dropping
> look through for the legacy core reflection methods. Also, the
> difficult question about calling getAnnotations() on a subclass -
> should it look through an inherited container, or return it? - goes
> away, as normal overriding policy gives good answers.
>
> Here's a simple model that Joe, Joel, and I are happy with:
>
> - @Repeatable(FooContainer.class) on @interface Foo {} causes
> @Foo @Foo in source to be containerized in the class file.
> (Rename @ContainedBy to @Repeatable.)
>
> - The rules for a well-formed relationship between Foo and
> FooContainer remain.
>
> - Core reflection's legacy methods return what's in the class file:
> - get[Declared]Annotation(Foo.class) returns nothing, like today.
> - get[Declared]Annotations() returns @FooContainer, like today.
>
> - Core reflection's new typed methods look through containers:
> - get[Declared]Annotations(Foo.class) returns @Foo @Foo.
>
> - An annotation writer may manually rewrite @FooContainer(...) as
> @Foo @Foo, and it will be containerized with perfect compatibility.
>
> - Language model's legacy methods follow core reflection:
> - Element.getAnnotation(Foo.class) returns nothing, like today.
> - Element[s].get[All]AnnotationMirrors() returns @FooContainer, like
> today
>
> - Language model's new typed method looks through:
> - Element.getAnnotations(Foo.class) returns @Foo @Foo.
> - We may add Element.getAnnotationMirrors(TypeElement) in future.
>
> I think the reduced semantic burden for an annotation type owner (no
> more @ContainedFor) and the stronger compatibility story for an
> annotation reader (no look through for legacy methods) are real
> improvements. We will specify and implement the model over the next
> month.
>
> Alex
This spec is way better,
to be sure, do you agree that getDeclaredAnnotations can be written like
this:
A[] getDeclaredAnnotations(Class<A> annotationClass) {
Repeatable repeatable =
annotationClass.getDeclaredAnnotation(Repetable.class);
if (repeatable != null) {
Annotation container = getDeclaredAnnotation(repeatable.value());
if (container != null) { // if there is a container annotation,
no single annotation can be present ?
return (A[])callValuesByReflection(container);
}
}
A annotation = getDeclaredAnnotation(annotationClass);
if (annotation == null)
return (A[])Arrays.newInstance(annotationClass, 0)
A[] annotations = (A[])Arrays.newInstance(annotationClass, 1);
annotations[0] = annotation;
return annotations;
}
cheers,
Rémi
More information about the enhanced-metadata-spec-discuss
mailing list