When you define a Java interface, it's possible to declare a method with type parameters, for example like this:
public interface ExampleInterface { <E extends Enum<E>> Class<E> options(); }
The same thing does not work in an annotation. This, for example, is illegal:
public @interface ExampleAnnotation { <E extends Enum<E>> Class<E> options(); }
I can get what I'm after by using the raw type Enum
:
public @interface ExampleAnnotation { @SuppressWarnings("rawtypes") Class<? extends Enum> options(); }
What exactly is the reason why it is not possible to declare annotation attributes with type parameters?
The @interface element is used to declare an annotation.
Annotation is defined like a ordinary Java interface, but with an '@' preceding the interface keyword (i.e., @interface ). You can declare methods inside an annotation definition (just like declaring abstract method inside an interface). These methods are called elements instead.
We can also explicitly specify the attributes in a @Test annotation. Test attributes are the test specific, and they are specified at the right next to the @Test annotation.
Type Annotations are annotations that can be placed anywhere you use a type. This includes the new operator, type casts, implements clauses and throws clauses. Type Annotations allow improved analysis of Java code and can ensure even stronger type checking.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With