Annotation attributes with type parameters
The The Java™ Language Specification Third Edition says:
The following restrictions are imposed on annotation type declarations by virtue of their context free syntax:
- Annotation type declarations cannot be generic.
- No extends clause is permitted. (Annotation types implicitly extend annotation.Annotation.)
- Methods cannot have any parameters
- Methods cannot have any type parameters
- Method declarations cannot have a throws clause
I think it is possible, but it requires lots of additions to language spec, which is not justified.
First, for you enum example, you could use Class<? extends Enum<?>> options
.
There is another problem in Class<? extends Enum> options
: since Enum.class
is a Class<Enum>
which is a Class<? extends Enum>
, it's legal to options=Enum.class
That can't happen with Class<? extends Enum<?>> options
, because Enum
is not a subtype of Enum<?>
, a rather accidental fact in the messy raw type treatments.
Back to the general problem. Since among limited attribute types, Class
is the only one with a type parameter, and wildcard usually is expressive enough, your concern isn't very much worth addressing.
Let's generalize the problem even further, suppose there are more attribute types, and wildcard isn't powerful enough in many cases. For example, let's say Map
is allowed, e.g.
Map<String,Integer> options();
options={"a":1, "b":2} // suppose we have "map literal"
Suppose we want an attrbite type to be Map<x,x>
for any type x
. That can't be expressed with wildcards - Map<?,?>
means rather Map<x,y>
for any x,y
.
One approach is to allow type parameters for a type: <X>Map<X,X>
. This is actually quite useful in general. But it's a major change to type system.
Another approach is to reinterpret type parameters for methods in an annotation type.
<X> Map<X,X> options();
options={ "a":"a", "b":"b" } // infer X=String
this doesn't work at all in the current understanding of method type parameters, inference rules, inheritance rules etc. We need to change/add a lot of things to make it work.
In either approaches, it's a problem how to deliver X
to annotation processors. We'll have to invent some additional mechanism to carry type arguments with instances.
Section 9.6 of the Java Language Specification describes annotations. One of the sentences there reads:
It is a compile-time error if the return type of a method declared in an annotation type is any type other than one of the following: one of the primitive types, String, Class and any invocation of Class, an enum type (§8.9), an annotation type, or an array (§10) of one of the preceding types. It is also a compile-time error if any method declared in an annotation type has a signature that is override-equivalent to that of any public or protected method declared in class Object or in the interface annotation.Annotation.
And then it says the following, which is I think the key to this problem:
Note that this does not conflict with the prohibition on generic methods, as wildcards eliminate the need for an explicit type parameter.
So it suggests that I should use wildcards and that type parameters are not necessary. To get rid of the raw type Enum
, I just have to use Enum<?>
as irreputable suggested in his answer:
public @interface ExampleAnnotation {
Class<? extends Enum<?>> options();
}
Probably allowing type parameters would have opened up a can of worms, so that the language designers decided to simply disallow them, since you can get what you need with wildcards.