Type
Annotations
Beginning with JDK 8, the
places in which annotations can be used has been expanded. As mentioned
earlier, annotations were originally allowed only on declarations. However,
with the advent of JDK 8, annotations can also be specified in most cases in
which a type is used. This expanded aspect of annotations is called type annotation. For example, you can
annotate the return type of a method, the type of this within a method, a cast, array levels, an inherited class, and
a throws clause. You can also
annotate generic types, including generic type parameter bounds and generic
type arguments. (See Chapter 14 for a discussion of generics.)
Type annotations are
important because they enable tools to perform additional checks on code to
help prevent errors. Understand that, as a general rule, javac will not perform these checks, itself. A separate tool is
used for this purpose, although such a tool might operate as a compiler plug-in.
A type annotation must
include ElementType.TYPE_USE as a
target. (Recall that valid annotation targets are specified using the @Target annotation, as previously
described.) A type annotation applies to the type that the annotation precedes.
For example, assuming some type annotation called @TypeAnno, the following is legal:
void myMeth() throws @TypeAnno
NullPointerException { // ...
Here, @TypeAnno annotates NullPointerException
in the throws clause.
You can also annotate the
type of this (called the receiver). As you know, this is an implicit argument to all
instance methods and it refers to the invoking object. To annotate its type
requires the use of another new JDK 8 feature. Beginning with JDK 8, you can
explicitly declare this as the first
parameter to a method. In this declaration, the type of this must be the type of its class; for example:
class SomeClass {
int myMeth(SomeClass this, int i, int j) { //
...
Here, because myMeth( ) is a method defined by SomeClass, the type of this is SomeClass. Using this declaration, you can now annotate the type of
this. For example, again assuming
that @TypeAnno is a type annotation,
the following is legal:
int myMeth(@TypeAnno SomeClass this, int i, int
j) { // ...
It is important to understand
that it is not necessary to declare this
unless you are annotating it. (If this
is not declared, it is still implicitly passed. JDK 8 does not change this fact.) Also, explicitly declaring this does not change any aspect of the
method’s signature because this is
implicitly declared, by default. Again, you will declare this only if you want to apply a type annotation to it. If you do
declare this, it must be the first parameter.
The following program shows a
number of the places that a type annotation can be used. It defines several
annotations, of which several are for type annotation. The names and targets of
the annotations are shown here:
Notice that @EmptyOK, @Recommended, and @What
are not type annotations. They are included for comparison purposes. Of special
interest is @What, which is used to
annotate a generic type parameter declaration and is another new annotation
feature added by JDK 8. The comments in the program describe each use.
Demonstrate several type annotations.
import java.lang.annotation.*;
import java.lang.reflect.*;
//A marker annotation that can be applied to a
type.
@Target(ElementType.TYPE_USE)
@interface TypeAnno { }
//Another marker annotation that can be applied
to a type.
@Target(ElementType.TYPE_USE)
@interface NotZeroLen {
}
//Still another marker annotation that can be
applied to a type.
@Target(ElementType.TYPE_USE)
@interface Unique { }
//A parameterized annotation that can be
applied to a type. @Target(ElementType.TYPE_USE)
@interface MaxLen { int value();
}
//An annotation that can be applied to a type
parameter.
@Target(ElementType.TYPE_PARAMETER)
@interface What { String description();
}
//An annotation that can be applied to a field
declaration.
@Target(ElementType.FIELD)
@interface EmptyOK { }
//An annotation that can be applied to a method
declaration.
@Target(ElementType.METHOD)
@interface Recommended { }
//Use an annotation on a type parameter.
class TypeAnnoDemo<@What(description =
"Generic data type") T> {
Use a type annotation on a constructor. public
@Unique TypeAnnoDemo() {}
Annotate the type (in this case String), not
the field. @TypeAnno String str;
This annotates the field test. @EmptyOK String
test;
//Use a type annotation to annotate this (the
receiver).
public int f(@TypeAnno TypeAnnoDemo<T>
this, int x) {
return 10;
}
//Annotate the return type.
public @TypeAnno Integer f2(int j, int k) {
return j+k;
}
// Annotate the method declaration.
public @Recommended Integer f3(String str) {
return str.length() / 2;
}
// Use a type annotation with a throws clause.
public void f4() throws @TypeAnno
NullPointerException { // ...
}
// Annotate array levels.
String @MaxLen(10) [] @NotZeroLen [] w;
// Annotate the array element type. @TypeAnno
Integer[] vec;
public static void myMeth(int i) {
// Use a type annotation on a type argument.
TypeAnnoDemo<@TypeAnno Integer> ob =
new TypeAnnoDemo<@TypeAnno Integer>();
// Use a type annotation with new.
@Unique TypeAnnoDemo<Integer> ob2 = new
@Unique TypeAnnoDemo<Integer>();
Object x = new Integer(10);
Integer y;
// Use a type annotation on a cast.
y = (@TypeAnno Integer) x;
}
public static void main(String args[]) {
myMeth(10);
}
// Use type annotation with inheritance clause.
class SomeClass extends @TypeAnno
TypeAnnoDemo<Boolean> {}
Although what most of the
annotations in the preceding program refer to is clear, four uses require a bit
of discussion. The first is the annotation of a method return type versus the
annotation of a method declaration. In the program, pay special attention to
these two method declarations:
// Annotate the return type.
public @TypeAnno Integer f2(int j, int k) {
return j+k;
}
// Annotate the method declaration.
public @Recommended Integer f3(String str) {
return str.length() / 2;
}
Notice that in both cases, an
annotation precedes the method’s return type (which is Integer). However, the two annotations annotate two different
things. In the first case, the @TypeAnno
annotation annotates f2( )’s
return type. This is because @TypeAnno has
its target specified as ElementType.TYPE_USE, which means that
it can be used to annotate type uses. In the second case, @Recommended annotates the method declaration, itself. This is
because @Recommended has its target
specified as ElementType.METHOD. As
a result, @Recommended applies to
the declaration, not the return type. Therefore, the target specification is
used to eliminate what, at first glance, appears to be ambiguity between the
annotation of a method declaration and the annotation of the method’s return
type.
One other thing about
annotating a method return type: You cannot annotate a return type of void.
The second point of interest
are the field annotations, shown here:
Annotate the type (in this case String), not
the field.
@TypeAnno String str;
This annotates the field test.
@EmptyOK String test;
Here, @TypeAnno annotates the type String,
but @EmptyOK annotates the field test. Even though both annotations
precede the entire declaration, their targets are different, based on the
target element type. If the annotation has the ElementType.TYPE_USE target, then the type is annotated. If it has ElementType_FIELD as a target, then the
field is annotated. Thus, the situation is similar to that just described for
methods, and no ambiguity exists. The same mechanism also disambiguates
annotations on local variables.
Next, notice how this (the receiver) is annotated here:
public int f(@TypeAnno TypeAnnoDemo<T>
this, int x) {
Here, this is specified as the first parameter and is of type TypeAnnoDemo (which is the class of
which f( ) is a member). As
explained, beginning with JDK 8, an instance method declaration can explicitly
specify the this parameter for the
sake of applying a type annotation.
Finally, look at how array
levels are annotated by the following statement:
String @MaxLen(10) [] @NotZeroLen [] w;
In this declaration, @MaxLen annotates the type of the first
level and @NotZeroLen annotates the
type of the second level. In this declaration
@TypeAnno Integer[] vec;
the element type Integer is annotated.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.