Lloyd Chambers wrote:
Thanks everyone for the very interesting followup!
I've read the posts, etc, but it's still unclear to me whether
@Override is legal or not on a sub-interface (in JDK 1.6). My original
intent was to have the compiler enforce the claim: "This method MUST
exist in a super-interface".
Implementation doesn't matter for my intended purpose.
- Every @Configured that is a PropertyBag needs to redeclare the
getProperty() method so it can add annnotations to it;
- No @Configured should have the getProperty() method unless it IS_A
PropertyBag.
We have this case not just for PropertyBag, but for several other
interfaces as well eg (Named).
======== Annnotations and interface hierarchies ==========
What does it mean to have an interface hierarchy with successive
re-declarations of the same method?
Good question. I've done a lot a annotation processing lately, mainly
for JMXA. The first thing to remember
is that any AnnotatedElement has at most one instance of any annotation
(because AnnotatedElement.getAnnotation
can only return one annotation of any type, mirroring the fact that
multiple declarations of the same
annotation on the same element are rejected by the compiler).
getAnnotation will return the value of the annotation on
the element on which it is called, if present. For classes, if the
annotation definition contains the @Inherited
meta-annotation, getAnnotation will return the first instance of the
annotation found in following the superclass
inheritance chain. Interface inheritance has NO effect on this (see
the javadoc for java.lang.annotation.Inherited),
and this can definitely be a problem.
For my own purposes (since I want to see annotations on interfaces as
well as classes), I wrote some simple utilities
to represent the class and interface inheritance as a graph, and then
use a reversed post-order traversal of the
graph to determine the search order when looking for annotations. That
way I can see annotations on interfaces
as well as classes.
-- Do the annotations accumulate when programs go to use
them? (Depends on how the API is used I think)
No, but you can find all of them by exploring the class hierarchy if
needed (or yes, you can write code that
effectively accumulates annotations if you wish, depending on how you
view my answer :-)).
-- Only one annotation of a given type is possible on each
target in a given class/interface. But sub-interfaces can add another
annotation of the same type. How does this interact with the API, and
what is it supposed to mean for a system like HK2?
It completely depends on the implementation. The most straightforward
case is to just call getAnnotation on the class,
in which case (for inherited annotations) you walk up the superclass
chain until you get an annotation, or end at Object.
But any implementation is free (as in my case) to do whatever it wants
to. That's why the @Inherited meta-annotation is
not so useful: it really means NOTHING outside of the context of a
particular implementation of annotation processing.
I can see two useful models here:
- If an annotation acts like a constraint, it probably makes sense
to accumulate annotation information and act on all of it
- In most cases, probably what you want is simply the most specific
annotation of a given type. @Inherited does this in simple cases, but
more complex cases require directly writing code to analyze the class
hierarchy.
There are probably other models that I haven't thought of that make
sense.
Example: (http://en.wikipedia.org/wiki/Lichen)
How many @GrowableStuff annotations exist on Lichen?
How many @Override annotations?
And is this legal in JDK 6 or not?
Not sure about @Override, it sounds like (from other discussions) that
it is legal in JDK 6 (but not in JDK 5).
The other annotations should be legal in any case.
public interface Growable {
@GrowableStuff(...) public void grow();
}
public interface Mycobiont extends Growable {
@Override @GrowableStuff(...) @MycobiontStuff public void grow();
}
public interface Phycobiont extends Growable {
@Override @GrowableStuff(...) @PhycobiontStuff public void grow();
}
public interface Lichen extends Mycobiont, Phycobiont {
@Override @GrowableStuff(...) @LichenStuff public void grow();
}
What I THINK will happen for the methods (I need to check this, it's
important for JMXA as well)
is that you will get the annotations on the Method object for the
method as defined in a
particular class. In your example,
Lichen.class.getDeclaredMethod( "grow" ).getAnnotations()
should return the @GrowableStuff(...) and @LichenStuff annotations
(@Override is annotated
with source retention, so the compiler will discard it).
On the other hand,
Phycobiont.class.getDeclaratedMethod( "grow" ).getAnnotations()
should return @GrowableStuff( ... ) (with different info than on
Lichen) and @PhycobiontStuff.
Ken.