After talking with Josh, I've decided to live within one design
constraint of the existing framework: for any annotation location and
annotation class, there is either zero or one matching annotations.
This forbids some things like subtyping between annotations, and
multiple instances of the same annotation on an element.
* Proposal 1: An annotation is allowed to extend/implement any number
of interfaces.
You might want to use this for marker interfaces, or define an
interface that defines
several elements/methods, and any annotation that implements that
interface would be
required to implement those methods.
Note that the interface would just be a normal interface that
could be implemented by
classes as well (although this wouldn't be recommended practice).
interfaces can't
define default values.
This would allow you to define a standard set of element names
that were used by
by set of specific annotations, and allow internal API's that
worked with any annotation
from that set.
* Proposal 2 (requires proposal 1):
An annotation can define an element that returns an interface that
extends
java.lang.annotation.Annotation. When applying such an annotation
in the source code, the
value used there must be some concrete annotation that extends
that interface.
Right now, the only values allowed for annotation elements are:
primitives, String, Class, enums, specific annotation classes, and
arrays
This proposal would allow you to define annotations that, when
applied in source code,
accepted as an element value any one of a number of specific
annotations. By defining the
element to return a value of type Annotation, you can define an
element where an arbitrary
Annotation can be provided. For example, consider example where
the Baz annotation can be
applied with either a Foo or a Baz annotation as an element:
public interface AnnotationWithId extends Annotation {
int id();
}
public @interface Foo extends AnnotationWithId {
int id(); // this could be omitted, since it is defined in the
interface
String msg();
}
public @interface Bar extends AnnotationWithId {
int id() default 0; // couldn't be omitted, since the interface
can't give a default value
String date();
}
public @interface Baz {
AnnotationWithId annotation(); // can supply a @Foo or @Bar here
String reason();
}
public Test {
@Baz(annotation=@Foo(id=17, msg="testing"), reason="because")
public int test() { return 17; }
}
I suspect there may be issues I hadn't considered, so I'd appreciate
your feedback on this.
My current thought is to not make this part of JSR-308, but directly
submit it to the JSE7 effort.
Bill