Java Annotation annotation mechanism

Brief introduction

Annotation provides a way to program elements with any information or any metadata (Metadata) association. In some ways, annotation as modifier as used and applied to packages, types, constructors, methods, member variables, parameters, local variables in a statement. This information is in the annotation of "name = value" storage structure. annotation type is an interface that provides access to their information by way of reflection java API.

It can be used as an annotation program elements (classes, methods, member variables, etc.) associated with any information. It should be noted that there is a fundamental unspoken rules here: annotaion not affect the execution of program code, whether adding, deleting annotation, code consistent execution. In addition, although some annotation be accessed at runtime via reflection java api method, and the java language interpreter ignores these annotation at work. It is because of java virtual machine ignores the annotation, led to the annotation type is "ineffective" in the code; only if the information annotation types accessed and processed by some supporting tools. To herein encompasses standard annotation and meta-type annotation, annotation accompany these types of tools is java compiler (of course they are treated in a particular way).
For the above reasons, annotation in the use of very simple. It may be a local variable in a named NonNull annotation type indicated, as the assertion of the local variables can not be assigned a null value. And we can write a complete set of annotation code analysis tool, use it to parse the code has a front variable, and try to verify this assertion. Of course, this code does not have to write your own. After the JDK installation can be found in the JDK / bin directory tool called "apt", which provides a framework for dealing with the annotation: annotation after it starts scanning the source code, and call us to complete our defined annotation processor the work to be done (such as authentication assertion in the previous example). Here, powerful annotation tools XDoclet seems to be kind of a substitute, along with our depth, we will be more convinced of this.

In JAVA applications, we often encounter some need to use the template code. For example, to write a JAX-RPC web service, we have to provide a pair of interface and implementation as a template code. If you use the annotation for remote access method code is modified, then this template will be able to use the tool automatically generates.
In addition, some need to use the API affiliated with the program code files simultaneously maintain. For example, JavaBeans requires a BeanInfo Class Bean with a use / maintenance at the same time, and it also requires a EJB Deployment descriptor. This time using the annotation in a program to maintain the sidecar file information will be very convenient and reduces errors.

Annotation concepts and syntax

First, the key concept is to be understood that annotation label information or metadata associated with a program element. It never affect the execution of java programs, but, for example, a compiler warning or an impact as documentation generator and other auxiliary tools.
The following is a list of commonly used annotation, we should note between the annotation and the annotation of different types:
A.annotation:
annotation using the new syntax in java5.0 brought it behaves very similar to the public, final modifier such . Each annotation has a name and a number of members of> = 0. The members of each annotation has a name and name = value (like javabean) value pairs are called, name = value loaded the annotation information.
B.annotation type:
annotation type defines the annotation name, type, member default. A annotation type can be said to be a special java interfaces, its member variables are limited and need to use the new syntax for declaring annotation types. When we visit annotation through reflection java api, the return value is an object that implements the annotation type interface, we can easily access the annotation to its members through access to this object. The following sections mentioned three standard annotation type java.lang package java5.0 included.
C.annotation members:
annotation in the annotation type of a member in the form of non-parametric method is declared. Its method name and return value defines the name and type of the member. In a specific default syntax: Allow declare any annotation member defaults: a annotation can name = value pairs value as annotation member does not define a default value, of course, also possible to use name = value pairs to cover the other members of the default value. This is somewhat similar type of inherited characteristics, the parent class constructor can be used as the default constructor for subclasses, but can also be overridden by subclasses.
D.marker annotation types:
a type annotation is not a member of definitions is called the marker annotation. This type of annotation using only their presence or absence to provide information to us. Override as to say later.
Annotation-E.meta:
Meta element annotation -annotation also known, which is used to declare the type of annotation annotation. Java5.0 provides some standard meta -annotation type. Target described below, retention is meta-annotation.
F.target:
Annotation The target is to be a marked program elements. illustrates the modified target annotation target range: annotation may be used for packages, types (classes, interfaces, enumerations, annotation type), a member type (method, constructor, member variables enumerated value), method arguments and local variables (e.g., variable loop, catch parameters). Use a target in the annotation type declaration can be more clear that it modifies the target.
G.retention:
The retention annotation defines the length of time reserved annotation: some annotation appears only in the source code, the compiler is discarded; and others in the class file was compiled; compiled class in the annotation file may be VM ignored, while others in the class is loaded will be read (Please note does not affect the implementation of the class, because annotation and class in the use of a separated). Using this meta-annotation can restrict annotation "life cycle."
H.metadata:
Since the metadata is widely used in various computer development process, so when we are talking here generally refers to metadata i.e. metadata annotation information is loaded or annotation itself.

Annotation work

Prior to version 5.0 of the Java platform already has a number of ad hoc annotation mechanisms. For example, using a transient modifier to identify a member variable should be ignored in the sequence of the subsystem. And also a javadoc tag @deprecated This ad hoc annotation for explaining a method obsolete. Since Java5.0 release, 5.0 platform provides a formal annotation feature: allows developers to define, use your own annoatation type. This feature of grammar and syntax of a descriptive annotation declared a defined annotation types, read annotaion the API, a modified class annotation files using an annotation processing tool (apt) components.
annotation does not directly affect the semantics of the code, but the way it can work is seen as a tool or a similar program library, which will in turn have an impact on the semantics of the running program. annotation can be, class file is either read from the source file is reflected in various ways at runtime.
Of course annotation in a way to make more complete javadoc tag. Under normal circumstances, if the document marked impact on java or java is used to generate the document, then it should serve as a javadoc tag; otherwise it will serve as an annotation.

Annotation and reflection

In the reflection API java5.0 Java.lang.reflect is expanded to provide the ability to read annotation runtime. Let's review stated before: after a annotation type is defined as runtime retention, it is visible when the class file is loaded annotation is saved in the class file at runtime virtual machine will be read. So help us reflect how to access class in the annotation of it?
Below will be used in java.lang.reflect new features annotation, where java.lang.reflect.AnnotatedElement is important interface, which represents the program members to provide query annotation capabilities. This interface is java.lang.Package, java.lang.Class realized and implemented indirectly Method class, the Constructor class, the java.lang.reflect the Field class. The method parameters may annotation by Method class, Constructor class getParameterAnnotations () method is obtained.
isAnnotationPresent () method is useful for checking marker annotation and marker annotation because no member variables, so long as we know whether to use the class methods annotation modify it. And when dealing with a member of the annotation, we have to get membership information annotation of (member name, member value) by using getAnnotation () method. Here we see a beautiful java annotation system: If the annotation exists, then the realization of the corresponding object annotation type interface will be getAnnotation () method returns, and then call a member method defined in annotation types is readily available to any member value.

way annotation type declaration

Typically, an application does not have to define annotation type, but the definition annotation type is not difficult. Annotation type declaration to declare a general interface is very similar, the only difference is it uses the "@" symbol in front of the interface keyword.
Each annotation type defines a method declaration annotation type members, but do not have the method declaration statement parameters or abnormal; the type of the return value of the method is limited in the following range: primitives, String, Class, enums , annotation , and in front of an array of type ; method may have default values.
Here is a simple annotation type declaration:

      
      
1
2
3
4
5
6
7
8
      
      
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
boolean isKey () default false; // for determining whether the primary key column in the database
boolean canNull () default true; // when it is determined not null for insertion column has the value
String value () default "[ColumnName]"; // corresponding to the column name in the database
}

annotation method of modifying declarative

annotation is a modifier, such as other modifiers can be generally used (e.g., public, static, final). Annotaions idiom is used in front of other modifiers. annotations by the "@ + annotation type + members with brackets - the list of values" component. The values of these members must be compile-time constants (ie unchanged at runtime).
Here is a method using the Column annotation statement:

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
      
      
// Since the correspondence table and attribute names in the database and may not annotate
@Table(CV.TN_CHARTYPE)
public class CharType {
@Column(isKey=true,value=CV.DB_ID)
private String id;
@Column(CV.CT_CN_NAME)
private String name;
@Column(CV.CT_CN_DESC)
private String describe;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
}

## 没有成员的annotation类型声明
当声明一个没有成员的annotation类型声明时,可使用以下方式:

      
      
1
2
3
4
5
6
7
8
      
      
/**
* Indicates that the specification of the annotated API element
* is preliminary and subject to change.
*/
public @interface Preliminary { }
作为上面没有成员的annotation类型声明的简写方式:
@Preliminary public class TimeTravel { ... }

只有唯一一个成员annotations的声明

如果在annotations中只有唯一一个成员,则该成员应命名为value:

      
      
1
2
3
4
5
6
7
8
9
      
      
/**
* Associates a copyright notice with the annotated API element.
*/
public @interface Copyright {
String value();
}
更为方便的是对于具有唯一成员且成员名为value的annotation(如上文),在其使用时可以忽略掉成员名和赋值号(=):
@Copyright("2002 Yoyodyne Propulsion Systems")
public class OscillationOverthruster { ... }

定义Annotation的例子

使用annotation来描述那些被标注的成员是不稳定的,需要更改

      
      
1
2
3
4
5
6
7
8
9
10
11
      
      
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
public @interface Unstable {}
使用Author这个annotation定义在程序中指出代码的作者
public @interface Author {
/** 返回作者名 */
String value();
}

以下的example更加复杂。Reviews annotation类型只有一个成员,但是这个成员的类型是复杂的:由Review annotation组成的数组。Review annotation类型有3个成员:枚举类型成员grade、表示Review名称的字符串类型成员Reviewer、具有默认值的字符串类型成员 Comment。

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
      
      
import java.lang.annotation.*;
/**
* Reviews annotation类型只有一个成员,
* 但是这个成员的类型是复杂的:由Review annotation组成的数组
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Reviews {
Review[] value();
}
/**
* Review annotation类型有3个成员:
* 枚举类型成员grade、
* 表示Review名称的字符串类型成员Reviewer、
* 具有默认值的字符串类型成员Comment。
*/
public @interface Review {
// 内嵌的枚举类型
public static enum Grade { EXCELLENT, SATISFACTORY, UNSATISFACTORY };
// 下面的方法定义了annotation的成员
Grade grade();
String reviewer();
String comment() default "";
}

最后,我们来定义一个annotation方法用于罗列出类运行中所有的unchecked异常。这个 annotation类型将一个数组作为了唯一的成员。数组中的每个元素都是异常类。为了加强对未检查的异常(此类异常都是在运行时抛出)进行报告,我们可以在代码中对异常的类型进行限制:

      
      
1
2
3
      
      
public @interface UncheckedExceptions {
Class<? extends RuntimeException>[] value();
}

一个使用annotation的实例

结合上面所讲的,我们在这里建立一个简单的基于annotation测试框架。首先我们需要一个annotation类型来表示某个方法是一个应该被测试工具运行的测试方法。

      
      
1
2
3
4
5
6
7
8
9
10
11
      
      
package com.kr1;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Anno {
}

值得注意的是annotaion类型声明是可以标注自己的,这样的annotation被称为“meta-annotations”。
在上面的代码中,@Retention(RetentionPolicy.RUNTIME)这个meta-annotation表示了此类型的annotation将被虚拟机保留使其能够在运行时通过反射被读取。而@Target(ElementType.METHOD)表示此类型的annotation只能用于修饰方法声明。
下面是一个简单的程序,其中部分方法被上面的annotation所标注:

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
      
      
public class Foo {
@Test public static void m1() { }
public static void m2() { }
@Test public static void m3() {
throw new RuntimeException("Boom");
}
public static void m4() { }
@Test public static void m5() { }
public static void m6() { }
@Test public static void m7() {
throw new RuntimeException("Crash");
}
public static void m8() { }
}

测试

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      
      
import java.lang.reflect.*;
public class RunTests {
public static void main(String[] args) throws Exception {
int passed = 0, failed = 0;
for (Method m : Class.forName(args[0]).getMethods()) {
if (m.isAnnotationPresent(Test.class)) {
try {
m.invoke(null);
passed++;
} catch (Throwable ex) {
System.out.printf("Test %s failed: %s %n", m, ex.getCause());
failed++;
}
}
}
System.out.printf("Passed: %d, Failed %d%n", passed, failed);
}
}

这个程序从命令行参数中取出类名,并且遍历此类的所有方法,尝试调用其中被上面的测试annotation类型标注过的方法。在此过程中为了找出哪些方法被annotation类型标注过,需要使用反射的方式执行此查询。如果在调用方法时抛出异常,此方法被认为已经失败,并打印一个失败报告。最后,打印运行通过/失败的方法数量。
下面文字表示了如何运行这个基于annotation的测试工具:

      
      
1
2
3
4
      
      
$ java RunTests Foo
Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom
Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash
Passed: 2, Failed 2

Annotation分类

  1. 内建Annotation
    Java5.0版在java语法中经常用到的内建Annotation:
    @Deprecated用于修饰已经过时的方法;
    @Override用于修饰此方法覆盖了父类的方法(而非重载);
    @SuppressWarnings用于通知java编译器禁止特定的编译警告。
  2. 使用标准Annotation
    A.Override:
    java.lang.Override 是一个marker annotation类型,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。 这个annotaton常常在我们试图覆盖父类方法而确又写错了方法名时发挥威力。 使用方法极其简单:在使用此annotation时只要在被修饰的方法前面加上@Override。 下面的代码是一个使用@Override修饰一个企图重载父类的toString方法,而又存在拼写错误的sample:
            
            
    1
    2
    3
    4
            
            
    @Override
    public String toString() {
    return "[" + super.toString() + "]";
    }

B.Deprecated:
同样Deprecated也是一个marker annotation。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。而且这种修饰具有一定的 “延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为 @Deprecated,但编译器仍然要报警。
值得注意,@Deprecated这个annotation类型和javadoc中的 @deprecated这个tag是有区别的:前者是java编译器识别的,而后者是被javadoc工具所识别用来生成文档(包含程序成员为什么已经过时、它应当如何被禁止或者替代的描述)。
在java5.0,java编译器仍然象其从前版本那样寻找@deprecated这个javadoc tag,并使用它们产生警告信息。但是这种状况将在后续版本中改变,我们应在现在就开始使用@Deprecated来修饰过时的方法而不是 @deprecated javadoc tag。
下面是一段使用@Deprecated的代码:

      
      
1
2
3
4
5
      
      
/**
* 这里是javadoc的@deprecated声明.
* @deprecated No one has players for this format any more. Use VHS instead.
*/
@Deprecated public class Betamax { ... }

C.SuppressWarnings:
@SuppressWarnings 被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0,sun提供的javac编译器为我们提供了-Xlint选项来使编译器对合法的程序代码提出警告,此种警告从某种程度上代表了程序错误。例如当我们使用一个generic collection类而又没有提供它的类型时,编译器将提示出”unchecked warning”的警告。
通常当这种情况发生时,我们就需要查找引起警告的代码。如果它真的表示错误,我们就需要纠正它。例如如果警告信息表明我们代码中的switch语句没有覆盖所有可能的case,那么我们就应增加一个默认的case来避免这种警告。
相仿,有时我们无法避免这种警告,例如,我们使用必须和非generic的旧代码交互的generic collection类时,我们不能避免这个unchecked warning。此时@SuppressWarning就要派上用场了,在调用的方法前增加@SuppressWarnings修饰,告诉编译器停止对此方法的警告。
SuppressWarning不是一个marker annotation。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。
annotation语法允许在annotation名后跟括号,括号中是使用逗号分割的name=value对用于为annotation的成员赋值:

      
      
1
2
      
      
@SuppressWarnings(value={"unchecked","fallthrough"})
public void lintTrap() { /* sloppy method body omitted */ }

在这个例子中SuppressWarnings annotation类型只定义了一个单一的成员,所以只有一个简单的value={…}作为name=value对。又由于成员值是一个数组,故使用大括号来声明数组值。
注意:我们可以在下面的情况中缩写annotation:当annotation只有单一成员,并成员命名为”value=”。这时可以省去”value=”。比如将上面的SuppressWarnings annotation进行缩写:

      
      
1
      
      
@SuppressWarnings({"unchecked","fallthrough"})

如果SuppressWarnings所声明的被禁止警告个数为一个时,可以省去大括号:

      
      
1
      
      
@SuppressWarnings("unchecked")

Meta-Annotation

Annotation 类型可以被它们自己所标注。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。这些类型和它们所支持的类在java.lang.annotation包中可以找到。如果需要更详细的信息可以参考jdk5.0手册。

  1. 再谈Target
    作为meta-annotation类型的Target,它描述了annotation所修饰的程序成员的类型。当一个annotation类型没有 Target时,它将被作为普通的annotation看待。当将它修饰一个特定的程序成员时,它将发挥其应用的作用,例如:Override用于修饰方法时,增加了@Target这个meta-annotation就使编译器对annotation作检查,从而去掉修饰错误类型的Override。
    Target meta-annotation类型有唯一的value作为成员。这个成员的类型是java.lang.annotation.ElementType[]类型的,ElementType类型是可以被标注的程序成员的枚举类型。
    2.Retention的用法
    我们在文章的开头曾经提到过Retention,但是没有详细讲解。Retention描述了annotation是否被编译器丢弃或者保留在class文件;如果保留在class文件中,是否在class文件被装载时被虚拟机读取。默认情况下,annotation被保存在class文件中,但在运行时并不能被反射访问。Retention具有三个取值:source、class、runtime,这些取值来自 java.lang.annotation.RetentionPolicy的枚举类型值。

Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。

  1. Of Documented
    of Documented is a meta-annotation type, described for other types of annotation program should be as members of the public API is labeled, it can be, for example, such tools javadoc of documentation.
    Documented is a marker annotation, no members.

4. Inherited
@ Inherited Meta-Annotation is a marker annotation, it describes a type of indexed is inherited. If using a modified @Inherited annotation type is used for a class, then this annotation is used in a subclass of this class.
Note: @Inherited annotation type is marked off class subclass inherits. Class does not inherit from annotation methods it from overloading it implements interface inheritance annotation, method.
It is worth pondering, when @Inherited annotation type annotation of the annotation Retention is RetentionPolicy.RUNTIME, the reflection API enhances this inheritance. If we use java.lang.reflect to query a @Inherited annotation type of annotation, reflecting code checks will start work: check the class and its parent class, until you find designated annotation types are found, or to reach the top class inheritance structure. 

Original: Big Box  Java Annotation annotation mechanism


Guess you like

Origin www.cnblogs.com/chinatrump/p/11615006.html