Java Annotations: Explored & Explained--转载

原文地址:http://www.javacodegeeks.com/2012/08/java-annotations-explored-explained.html

One of the many wonderful features of Java 5 SE is the introduction of the Annotations construct.
Annotations are tags that we can insert into our program source code for some tool to process it and make sense out of it. Annotations processing tools generally use Reflection API (of Java 5 SE) to process the code at source level on Java code or bytecode level to process the class files into which the compiler has placed the annotations. Java Annotations are wonderfully explained in many places around the web, but the only place where I could find a sensible and complete example was a hard bound book by Prentice Hall Publications named Core Java : Volume II – Advanced Features, authored by Cay S. Horstmann and Gary Cornell.

Almost all the places on web that try to explain Annotations miss the most crucial part of showing us an Annotation Processing Tool (APT) for our custom written annotations and the way to use it from our code. I have used the information from the book to build some Annotations for validating variables and initializing values in them from property files for my project. My observation of the lack of examples over the www for writing custom Java Annotations has motivated me to write this article. So, presenting to you a sample custom Java Annotation to help you write your own Annotations for whatever it is you may be doing.

I will take you through the NullValueValidate annotation whose purpose as its name suggests is to validate the variable it annotates to be containing a non null value. If it finds a null value while processing then it will throw aNullPointerException.

Declaring an Annotation

Lets begin by declaring our annotation. This declaration will be used by the code that intends to use the annotation to annotate the variables in its object.

01 package annotation.declaration;
02 import java.lang.annotation.Documented;
03 import java.lang.annotation.ElementType;
04 import java.lang.annotation.Retention;
05 import java.lang.annotation.RetentionPolicy;
06 import java.lang.annotation.Target;
07  
08 /**
09  * Null Value Validate is, as the name suggests an annotation to
10  * validate whether the parameter is null or not
11  * @author         Y.Kamesh Rao
12  *
13  */
14 @Documented
15 @Target(ElementType.FIELD)
16 @Retention(RetentionPolicy.RUNTIME)
17  
18 public @interface NullValueValidate {
19     String paramName();
20 }

Note the ‘@’(AT) symbol in front of the ‘interface’ keyword. This is the syntax used to declare an annotation. This is called an annotation interface. The methods of the interface correspond to the elements of the annotation. paramName() – This is the only element our annotation declaration consists of. It stores the name of the annotated field to display it in a message while processing. Note that the declaration looks like a function declaration. Actually, that is what it is. @interface actually declares a Java interface whose implementation is provided by the objects that use the annotation. Annotation processors receive the objects that use/implement the annotation and they call annotation interface methods to retrieve the annotation elements. In our case, the NullValueValidateAnnotationProcessor would receive the object of the class that has some fields annotated using the NullValueValidate annotation. This processor would then call the paramName() method to retrieve the value of this annotation element.

We use 3 of the Java provided Annotations to annotate the properties of our declaration. These are alternatively referred to as the Built-In Annotations and are used for ‘Annotating an Annotation’. (Well, there are much tougher tongue twisters than this). @Documented – Indicates that the annotation declaration has to be included while creating the docs for this project using JavaDocs. By default, Annotations are excluded from the documentation generated using the javadocscommand. @Target – Indicates the target elements in your java program to which the annotation shall be applied. It can either the Field, Method, Class or the whole Package itself. Our NullValueValidateannotation shall be applicable to only class fields. Here are the possible values taken by this Enum –

  • TYPE – Applied only to Type. A Type can be a Java class or interface or an Enum or even an Annotation.
  • FIELD – Applied only to Java Fields (Objects, Instance or Static, declared at class level).
  • METHOD – Applied only to methods.
  • PARAMETER – Applied only to method parameters in a method definition.
  • CONSTRUCTOR – Can be applicable only to a constructor of a class.
  • LOCAL_VARIABLE – Can be applicable only to Local variables. (Variables that are declared within a method or a block of code).
  • ANNOTATION_TYPE – Applied only to Annotation Types.
  • PACKAGE – Applicable only to a Package.

@Retention - Indicates the retention policy to be used for the annotation. In simple words, for long would we retain the annotation. There are three possible values –

  • SOURCE – Annotations are to be discarded by the compiler.
  • CLASS – Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.
  • RUNTIME – Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.

We have set the RetentionPolicy to be RUNTIME since we plan to process the annotations at runtime of the program.@Target and @Retention are also called Meta-Annotations.

Annotation Processing Tool

An annotation processor tool, parses the object it receives and takes programmed actions on finding the annotations it is processing in the object under scrutiny. Here is the annotation processor for our previously declared annotation –NullValueValidate.

01 package annotation.processor;
02  
03 import java.lang.annotation.Annotation;
04 import java.lang.reflect.Field;
05 import annotation.declaration.NullValueValidate;
06  
07 /**
08  * The class file to actually carry out the validations
09  * for the various validate annotations we have declared
10  * @author         Y.Kamesh Rao
11  */
12 public class NullValueValidateAnnotationProcessor {
13     /**
14      * Method to process all the annotations
15      * @param obj    The name of the object where
16      *               annotations are to be identified and
17      *               processed
18      */
19     public static void processAnnotations(Object obj) {
20         try {
21             Class cl = obj.getClass();
22  
23             // Checking all the fields for annotations
24             for(Field f : cl.getDeclaredFields()) {
25                 // Since we are Validating fields, there may be many
26                 // NullPointer and similar exceptions thrown,
27                 // so we need  to catch them
28                 try {
29                     // Processing all the annotations on a single field
30                     for(Annotation a : f.getAnnotations()) {
31                         // Checking for a NullValueValidate annotation
32                         if(a.annotationType() == NullValueValidate.class) {
33                             NullValueValidate nullVal = (NullValueValidate) a;
34                             System.out.println(‘Processing the field : ‘+ nullVal.paramName());
35  
36                             // Setting the field to be accessible from our class
37                             // is it is a private member of the class under processing
38                             // (which its most likely going to be)
39                             // The setAccessible method will not work if you have
40                             // Java SecurityManager configured and active.
41                             f.setAccessible(true);
42  
43                             // Checking the field for a null value and
44                             // throwing an exception is a null value encountered.
45                             // The get(Object obj) method on Field class returns the
46                             // value of the Field for the Object which is under test right now.
47                             // In other words, we need to send ‘obj‘ as the object
48                             // to this method since we are currently processing the
49                             // annotations present on the ‘obj‘ Object.
50                             if(f.get(obj) == null) {
51                                 throw new NullPointerException(‘The value of the field ‘+f.toString()+‘ can‘t be NULL.‘);
52                             else
53                                 System.out.println(‘Value of the Object : ‘+f.get(obj));
54                         }
55                     }
56                 catch(Exception e) {
57                     System.out.println(e.getMessage());
58                     e.printStackTrace();
59                 }
60             }
61         catch(Exception e) {
62             System.out.println(e.getMessage());
63             e.printStackTrace();
64         }
65     }
66 }

Most of the code is self explanatory with comments that it has. Please refer the code for detailed understanding of the same. Basically, it has a static method called processAnnotations that takes the object of the class which contains annotations that need to be processed. We then use Java Reflection API to process each of the Field in this received object parameter and take necessary actions of null value validation whenever we find a NullValueValidate Annotation on the field. If a null value is found, we throw the NullPointerException or we print the value on the console.

Annotation UsagePlease refer the following code that uses the NullValueValidate annotation that we just implemented. It also uses the NullValueValidateAnnotationProcessorto process the declared annotations on its field at runtime by calling it from its constructor. Also do note that the annotations are used in a similar fashion as access modifiers like private or public with the variable/field declarations. Usually a newline is entered for better readability of the code. Else, the annotation can very well exist in the same line as the variable/field declaration. The name of the annotation is preceded by an ‘@’(AT) symbol.

01 package annotation;
02  
03 import annotation.declaration.NullValueValidate;
04 import annotation.processor.NullValueValidateAnnotationProcessor;
05  
06 /** Main class to test the Annotations 
07  *   @author         Y.Kamesh Rao
08  */
09 public class AnnotationExample {
10     @NullValueValidate(paramName = ‘testVar1‘private String testVar1;
11     @NullValueValidate(paramName = ‘testVar2‘private String testVar2;
12  
13  
14     public AnnotationExample() {
15         testVar2 = ‘Testing the Null Value Validation...It Works...!‘;        
16          
17         // Calling the processor to process the annotations applied        
18         // on this class object.        
19         NullValueValidateAnnotationProcessor.processAnnotations(this);    
20     }    
21      
22     public static void main(String args[]) {
23         AnnotationExample ae = new AnnotationExample();    
24     }
25 }

Output

1 Processing the field:testVar1
2 Value of the Object:Testing the Null Value Validation...It Works...!
3 Processing the field:testVar2
4 The value of the field private java.lang.String annotation.AnnotationExample.testVar2 cannot be NULL.
5 java.lang.NullPointerException:The value of the field private java.lang.String annotation.AnnotationExample.testVar2 cannot be NULL.
6         at annotation.processor.NullValueValidateAnnotationProcessor.processAnnotation
7 (NullValueValidateAnnotationProcessor.java:66)
8         at annotation.AnnotationExample.(AnnotationExample.java:28)
9         at annotation.AnnotationExample.main(AnnotationExample.java:33)

Conclusion

I had a lot of fun doing this sample annotation program and now I have implemented many custom made Annotations to load properties from property files, validations of database field lengths, etc. Annotations greatly reduces the verbosity of the code thus making it much simpler and readable. Annotations can be used for logging, generating code dependent deployment descriptors and other mechanical and repetitive jobs. I had a lot of fun compiling this article for you guys. I hope you benefit from it.

时间: 2024-10-11 15:50:56

Java Annotations: Explored & Explained--转载的相关文章

理解Java ClassLoader机制(转载)

当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构: bootstrap classloader                |       extension classloader                |       system classloader bootstrap classloader -引导(也称为原始)类加载器,它负责加载Java的核心类. 在Sun的JVM中,在执行java的命令中使用-Xbootclasspath选项或使用 - D

Java 设计模式 单例模式(Singleton) [ 转载 ]

Java 设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创建对象 第一种(懒汉,线程不安全): 1 public class Singleton { 2 private static Singleton instance; 3 private Singleton (){} 4 5 public static Singleton getInstan

JAVA强制类型转换(转载+自己的感想) - stemon

JAVA强制类型转换(转载+自己的感想) - stemon 时间 2013-10-29 15:52:00  博客园-Java原文  http://www.cnblogs.com/stemon/p/3394464.html 首先声明:这篇文章的大部分是转载的,但是又有自己增加的部分,觉得这样才完整.我增加的部分只是自己的个人见解,推荐出来希望能得到大神的指正.再次说明我推荐出来是讨论的,虽然我潜水很久了,我依旧是菜鸟一枚. 在java中强制类型转换分为基本数据类型和 引用数据类型 两种,这里我们讨

Java.Annotations

0. Annotation Tricks http://developer.android.com/reference/java/lang/annotation/Annotation.html 0.1 Annotation 接口 "Defines the interface implemented by all annotations. Note that the interface itself is not an annotation, and neither is an interface

Java模式(适配器模式)【转载】

转载地址: http://blog.csdn.net/elegant_shadow/article/details/5006175 今天看了下Java中的适配器模式,以下就来小做下总结和谈谈感想,以便日后使用. 首先,先来先讲讲适配器.适配就是由“源”到“目标”的适配,而当中链接两者的关系就是适配器.它负责把“源”过度到“目标”.举个简单的例子,比如有一个“源”是一个对象人,他拥有2种技能分别是说日语和说英语,而某个岗位(目标)需要你同时回说日语.英语.和法语,好了,现在我们的任务就是要将人这个

JAVA的StringBuffer类(转载整理)____非常重要的一个类,线程安全,不用每次创建一个对象,以及和String的区别

核心部分转载自:http://www.cnblogs.com/springcsc/archive/2009/12/03/1616330.html StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和String不同,所以StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类. 所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入.删除等操作,使用StringBuffer要更加适合一些. 在S

如何成为java架构师(转载)

链接:https://www.zhihu.com/question/29031276/answer/54631312 来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 1:熟练使用各种框架,并知道实现原理(比如Spring, mybatis). 2: JVM虚拟机原理.调优,懂得JVM虚拟机能让你写出性能更好的代码. 3: 池技术,对象池,连接池,线程池 4:JAVA反射技术,写框架必备技术,但是有严重的性能问题,替代方案是JAVA字节码技术 5: nio,"直接内

java接口理解(转载)

今天和同事好好的讨论了java接口的原理和作用,发现原来自己的对接口的理解仅仅是局限在概念的高度抽象上,觉得好像理解了但是不会变化应用其实和没有理解差不多.以前看一个帖子说学习一个东西不管什么时候都要带着“这个东西是什么?”.“这个东西有什么作用?”和“这个东西怎样用?”三个问题,这三个问题回答上来了说明你对这个事物的理解达到了一定的高度. 今天还有一个比较深的经验是要学习到知识就要多和人交流.就像以前某个管理人员说得“要疯狂的交流”. 现在对于今天学到的接口部分做一个详细地总结: 接口的概念其

深入了解java线程池(转载)

出处:http://www.cnblogs.com/dolphin0520/ 本文归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执