原文地址: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; |
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 |
15 |
@Target (ElementType.FIELD) |
16 |
@Retention (RetentionPolicy.RUNTIME) |
18 |
public @interface NullValueValidate { |
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 javadocs
command. @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 NullValueValidate
annotation 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; |
03 |
import java.lang.annotation.Annotation; |
04 |
import java.lang.reflect.Field; |
05 |
import annotation.declaration.NullValueValidate; |
08 |
* The class file to actually carry out the validations |
09 |
* for the various validate annotations we have declared |
10 |
* @author Y.Kamesh Rao |
12 |
public class NullValueValidateAnnotationProcessor { |
14 |
* Method to process all the annotations |
15 |
* @param obj The name of the object where |
16 |
* annotations are to be identified and |
19 |
public static void processAnnotations(Object obj) { |
21 |
Class cl = obj.getClass(); |
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 |
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()); |
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 ); |
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.'); |
53 |
System.out.println( 'Value of the Object : ' +f.get(obj)); |
56 |
} catch (Exception e) { |
57 |
System.out.println(e.getMessage()); |
61 |
} catch (Exception e) { |
62 |
System.out.println(e.getMessage()); |
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 NullValueValidateAnnotationProcessor
to 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.
03 |
import annotation.declaration.NullValueValidate; |
04 |
import annotation.processor.NullValueValidateAnnotationProcessor; |
06 |
/** Main class to test the Annotations |
07 |
* @author Y.Kamesh Rao |
09 |
public class AnnotationExample { |
10 |
@NullValueValidate (paramName = 'testVar1' ) private String testVar1; |
11 |
@NullValueValidate (paramName = 'testVar2' ) private String testVar2; |
14 |
public AnnotationExample() { |
15 |
testVar2 = 'Testing the Null Value Validation...It Works...!' ; |
17 |
// Calling the processor to process the annotations applied |
18 |
// on this class object. |
19 |
NullValueValidateAnnotationProcessor.processAnnotations( this ); |
22 |
public static void main(String args[]) { |
23 |
AnnotationExample ae = new AnnotationExample(); |
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.
- Java 集合 fail-fast机制 [ 转载 ]
Java 集合 fail-fast机制 [转载] @author chenssy 摘要:fail-fast产生原因.解决办法 在JDK的Collection中我们时常会看到类似于这样的话: 例如,Ar ...
- Java.Annotations
Annotation 0. Annotation Tricks http://developer.android.com/reference/java/lang/annotation/Annotati ...
- JAVA强制类型转换(转载+自己的感想) - stemon
JAVA强制类型转换(转载+自己的感想) - stemon 时间 2013-10-29 15:52:00 博客园-Java原文 http://www.cnblogs.com/stemon/p/33 ...
- Java泛型详解 转载
转载地址:http://blog.csdn.net/jinuxwu/article/details/6771121 比较好的讲解: http://blog.csdn.net/lonelyroamer/ ...
- Java基础—反射(转载)
转载自: JAVA反射与注解 JAVA反射 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射机制是什么 反射 ...
- Java模式(适配器模式)【转载】
转载地址: http://blog.csdn.net/elegant_shadow/article/details/5006175 今天看了下Java中的适配器模式,以下就来小做下总结和谈谈感想,以便 ...
- Java问题排查工具箱[转载]
转载自:http://hellojava.info/?p=517 作者:阿里毕玄 问题排查除了最重要的解决思路和逻辑推导能力外,工具也是不可缺少的一部分,一个好用的工具可以事半功倍,甚至在某些情况下会 ...
- JAVA的StringBuffer类(转载整理)____非常重要的一个类,线程安全,不用每次创建一个对象,以及和String的区别
核心部分转载自:http://www.cnblogs.com/springcsc/archive/2009/12/03/1616330.html StringBuffer类和String一样,也用来代 ...
- java创建多线程(转载)
转载自:Java创建线程的两个方法 Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对 ...
随机推荐
- (1)java虚拟机概念和结构图
java虚拟机解构图一 java虚拟机解构图二 java虚拟机结构图三 [1]类加载系统 --->负责从文件系统或网络中加载class信息,存放至方法区的内存空间[2]java堆 ...
- jquery自动焦点图
效果预览:http://runjs.cn/detail/vydinibc 带左右箭头的自动焦点图:http://runjs.cn/detail/wr1d1keh html: <div clas ...
- android——创建camera应用(译)
只是选择相机部分来翻译.下面是主要内容 有些开发者可能需要Camera的接口,来定制自己程序的外观和特殊功能.创建自定义的Camera界面比使用using an Intent需要编写更多的代码,但是 ...
- [转]ubuntu zip 文件乱码解决 压缩乱码
ubuntu zip 文件乱码解决 压缩乱码 1.1 通过unzip行命令解压,指定字符集 unzip -O CP936 xxx.zip (用GBK, GB18030也可以) 有趣的是unzip的ma ...
- UVA 12436-Rip Van Winkle's Code(线段树的区间更新)
题意: long long data[250001]; void A( int st, int nd ) { for( int i = st; i \le nd; i++ ) data[i] = da ...
- HDU5046 Airport dancing links 重复覆盖+二分
这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮 ...
- HDU 3001 Travelling 3进制状压dp
题意:10个点,若干条边,边有花费,每个点最多走两次,求走过所有点,花费最少 分析:因为每个点最多走两次,所以联想到3进制,然后枚举状态,就行了(我也是照着网上大神的代码写的) #include &l ...
- Lua语法
1.Lua保留的关键字: and,bread,do,else,elseif,end,false,for,function,if,in,local,nil,not,or,repeat,return ,t ...
- 【学习干货】给coder的10个读书建议
1.知识更新非常快,大学一毕业就已经有40%的知识过时,一年不读书80%过时,三年不读书99%过时.这就要求我们不间断阅读,每年每月每星期每天都要阅读,只有长期的阅读才能不被淘汰:也只有长期阅读,才能 ...
- pip 安装python环境及打包
0.安装虚拟环境 pip install virtualenv virtualenv env1 source env1/bin/activate 1. 将包依赖信息保存在requireme ...