[JSR308] Proposal: Multiple Instance of same Annotation, Annotation Inheritance
Niko Matsakis
niko at alum.mit.edu
Fri Oct 3 04:25:20 EDT 2008
Hello,
I would like to propose that the current annotation system be extended
in two ways. The first would be to allow for multiple annotations of
the same type to be attached to the same program statement. This is
already mentioned in Section D.1 of the Type Annotations
Specification. The other would be to allow for inheritance among
annotations. Together, I think that these two ideas permit far more
flexibility than the current annotation scheme.
In this e-mail, I will attempt to outline a proposal, including
several points that remain undecided. I would be willing to implement
these changes, but I wanted to float a proposal and get some feedback
before I started diving in. In particular, I can't seem to find much
documentation on why multiple annotations and subtyping are not
permitted today: I assume it was out of a desire to keep the original
proposal simple, but perhaps there are strange interactions I am not
thinking of.
0. Problems I am trying to solve
Currently, the kind of data which can be encoded in annotations is
quite limited. It is generally possible to store data which has a
fixed structure, but it is much more difficult to encode more complex
data -- particularly hierarchical data -- without falling back to
strings that must be manually parsed.
As a trivial example, imagine trying to encode a tree which consists
of @Node annotations -- which may contain other nodes -- and @Leaf
annotations -- which cannot. Although the current annotation scheme
allows one kind of annotation to be embedded within another, the type
of annotation which is to be embedded must be specified. This means
that it would be possible to have @Nodes that contain either @Nodes or
@Leafs, but not both.
Under this proposal, such a scheme could be written as
public @interface Tree {}
public @interface Node extends Tree {
public Tree[] value();
}
public @interface Leaf extends Tree {}
which would allow for an annotation like:
@Node({
@Node({
@Leaf
}),
@Node({
@Node({
@Leaf,
@Leaf
})
})
})
Appendix D states that proposed changes to annotations are desirable
if "the additional changes are small, there is no better venue to add
such an annotation, and the new syntax would permit unanticipated
future uses." While I believe that this proposal fulfills all three
criteria, I think that it's primary purpose is to allow for
unanticipated future uses. As the success of XML, YAML, and other
such technologies has shown, the ability to encode structured data is
very powerful for a wide variety of uses. Today's annotations only
fulfill a small piece of that potential.
1. Duplicate annotations at a single location
It should be possible to place multiple instances of the same
annotation on the same program element. To accomodate this, the API
for accessing annotations will need to be extended: the current API
can only return a single annotation instance for a given annotation
type. I prefer the second alternative described in Appendix D.
Under this proposal, the existing AnnotatedElement interface would be
modified slightly. The current method
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
would be defined to return the first annotation of the given class (or
a subtype, see next section), or null if no such annotations are
present. A new method:
<T extends Annotation> T[] getAnnotations(Class<T> annotationClass)
would return an array containing all annotations in a given class.
The array will have length 0 if no such annotations exist.
The arrays returned by the methods getAnnotations(Class),
getAnnotations(), and getDeclaredAnnotations() will preserve the
ordering of the annotations as they were declared in the
original .java source file.
In some cases, it might not be desirable to allow multiple annotations
of the same class to co-exist. In this case, a new meta-annotation
can be used:
public @interface Repeatable {
public boolean value() = true;
}
which indicates explicitly whether or not an annotation can be used
multiple times on a single element. For backwards compatibility, the
compiler will ensure that annotations that are not meta-annotated with
@Repeatable cannot be used multiple times.
2. Subtyping among annotations
Currently, all annotation types are direct subtypes of
java.lang.Annotation. I propose to allow annotations to have a
subtyping relationship. To avoid complications, only single
inheritance would be permitted.
Sub-annotation types may define new properties not defined in the
supertype. They may also redefine existing properties from the
supertype so long as the new type of the property is a subtype of the
type defined in the supertype (i.e., return type covariance is
supported, as in other Java overrides).
3. Changes required to the implementation
The compiler would have to be changed to allow for multiple
annotations and to check the new error conditions (multiple
annotations without a @Repeatable attribute, errors in subtyping).
The java.lang API must be updated with the new getAnnotations() method.
4. Backwards compatibility issues
This section addresses some possible problems that might arise when
attempting to use old code -- either .java or .class files -- with a
newer runtime/compiler.
In terms of source compatibility, there are no backwards compatibility
problems with this proposal. Old code should continue to work exactly
as it does today. Only annotations which have the @Repeatable
attribute can be repeated, so those existing cases where only a single
instance of an annotation is semantically correct will continue to
cause errors as they do today. Likewise, code written under the
assumption that only a single instance of an annotation is permitted
will continue to operate correctly. If all annotation types could be
repeated by default, such code would still function, but it would only
process the first instance of any given annotation type.
In terms of binary compatibility, the major danger comes from the
changes to the AnnotatedElement interface which add an additional
method. This could be a problem if there are other implementors of
this interface outside of the Java standard library. I consider that
to be unlikely: however, it would also be an option to create a second
interface, AnnotatedElement2, which extended the original interface
and contains the new methods.
5. Possible changes
Of course, all the names of interfaces and methods in this proposal
could be changed. In addition, it might be desirable to allow any
annotation to be repeated by default, although this might allow some
annotations to be abused, and/or break old source code that expected
only one instance of a given annotation type. It is also not
necessary to allow both subtyping and multiple annotations at a given
location, though it is my belief that combining the two allows for
more benefit than either change individually.
regards,
Niko Matsakis
More information about the JSR308
mailing list