Annotation实战

现在annotation正在改变着java developer的一些开发生活,各种框架都在充分应用annotation来简化开发,我们来看看annotation到底是怎么一回事?
为什么引入annotation?
由于在Java的一些实际开发中,已经有了一些annotation出现的雏形.比方说webservice使用一些tag自动生成一些接口和实现,EJB的deployment descriptor对象,transient修饰符代表不能被serialization,@deprecated等。那么他们的共用特性是什么呢?尽管这些数据不会直接对Java的语义产生影响,但是是通过工具、库或者运行时程序的语义来散发影响力的。以这种方式出现的新功能称之为annotation机制。所以Java是在增强Java语言支持易于开发的背景下提出annotation机制的,annotation对于已有的Java机制的影响力主要在于Java source files、Java class files和运行时的reflection;主要关联java classes,interfaces,methods和fields。(,或者能够能够被javac compiler或者其他的工具读取、或者作为配置项能够被存贮在class文件中、或者在运行时用Java reflection API检测的到。)
虽然在第一天提出annotation这个特性,就一直在强调:annotion易于使用,但是应用开发者无须自己定义annotaion类型。但是不论是更好的使用现有的annotation类型,还是便于有朝一日自己确实需要扩展annotion类型,或者更好的理解开发模型,更好的理解程序的开发运行,都非常有必要了解一些annotation的。

我们看一下Meta-annotations,看到底如何自己定义一个annnotation类型。Meta-annotations主要包括四个部分:

1
2
3
4
Target
Retention
Documented
Inherited

Target里面的ElementType是用来指定Annotation类型可以用在哪一些元素上的.

1
2
3
4
5
6
7
Target(ElementType.TYPE)-can be applied to any element of a class
Target(ElementType.FIELD)-can be applied to a field or property
Target(ElementType.METHOD)-can be applied to a method level annotation
Target(ElementType.PARAMETER)-can be applied to the parameters of a method
Target(ElementType.CONSTRUCTOR)-can be applied to constructors
Target(ElementType.LOCAL_VARIABLE)-can be applied to local variables
Target(ElementType.ANNOTATION_TYPE)-indicates that the declared type itself is an annotation typ

Retention用来指定annotation类型保留在哪儿和多长时间。

1
2
3
RetentionPolicy.SOURCE-Annotations with this type will be by retained only at the source level and will be ignored by the compiler
RetentionPolicy.CLASS-Annotations with this type will be by retained by the compiler at compile time, but will be ignored by the VM
RetentionPolicy.RUNTIME-Annotations with this type will be retained by the VM so they can be read only at run-time

Documented用来指定这个annotation类型应当被javadoc工具文档化使用。
Inherited用来指定使用这个类型的类是个继承来的。
举一个简单的例子:
测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AnnotationTestableTeseCase {

@Test
public void go() throws SecurityException, ClassNotFoundException {
int passed = 0, failed = 0;
for (Method m : Class.forName(Foo.class.getName()).getMethods()) {
if (m.isAnnotationPresent(Testable.class)) {
try {
m.invoke(null);
passed++;
} catch (Throwable ex) {

failed++;
}
}
}
Assert.assertEquals(2, passed);
Assert.assertEquals(2, failed);
}
}

Annotation类型定义类:

1
2
3
4
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Testable {
}

使用Testable类型的客户端代码:

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
30
31
public class Foo {
@Testable
public static void m1() {
}

public static void m2() {
}

@Testable
public static void m3() {
throw new RuntimeException("Boom");
}

public static void m4() {
}

@Testable
public static void m5() {
}

public static void m6() {
}

@Testable
public static void m7() {
throw new RuntimeException("Crash");
}

public static void m8() {
}
}

Okey!
参考:
http://java.sun.com/developer/technicalArticles/releases/j2se15/
http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html
http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html
http://www.developer.com/java/other/article.php/10936_3556176_3