前言:
前不久在matrix上先后發(fā)表了《java annotation 入門》、《java annotation 手冊》兩篇文章,比較全面的對java annotation的語法、原理、使用三方面進行了闡述。由于《入門》中的簡單例程雖然簡單明了的說明了annotation用法,但給大家的感覺可能是意猶未見,所以在此行文《java annotation高級應用》,具體實例化解釋annotation和annotation processing tool(APT)的使用。望能對各位的有所幫助。
一、摘要:
《java annotation高級應用》具體實例化解釋annotation和annotation processing tool(APT)的使用。望能對各位的有所幫助。本文列舉了用于演示annotation的BRFW演示框架、演示APT的apt代碼實例,并對其進行較為深度的分析,希望大家多多提意見。
二、annotation實例分析
1.BRFW(Beaninfo Runtime FrameWork)定義:
本人編寫的一個annotation功能演示框架。顧名思義,BRFW就是在運行時取得bean信息的框架。
2.BRFW的功能:
A.源代碼級annotation:在bean的源代碼中使用annotation定義bean的信息;
B.運行時獲取bean數(shù)據(jù):在運行時分析bean class中的annotation,并將當前bean class中field信息取出,功能類似xdoclet;
C.運行時bean數(shù)據(jù)的xml綁定:將獲得的bean數(shù)據(jù)構造為xml文件格式展現(xiàn)。熟悉j2ee的朋友知道,這個功能類似jaxb.
3.BRFW框架:
BRFW主要包含以下幾個類:
A.Persistent類:定義了用于修飾類的固有類型成員變量的annotation.
B.Exportable類:定義了用于修飾Class的類型的annotation.
C.ExportToXml類:核心類,用于完成BRFW的主要功能:將具有Exportable Annotation的bean對象轉換為xml格式文本。
D.AddressForTest類:被A和B修飾過的用于測試目的的地址bean類。其中包含了地址定義所必需的信息:國家、省級、城市、街道、門牌等。
E.AddressListForTest類:被A和B修飾過的友人通訊錄bean類。其中包含了通訊錄所必備的信息:友人姓名、年齡、電話、住址(成員為AddressForTest類型的ArrayList)、備注。需要說明的是電話這個bean成員變量是由字符串類型組成的ArrayList類型。由于朋友的住址可能不唯一,故這里的住址為由AddressForTest類型組成的ArrayList.
從上面的列表中,可以發(fā)現(xiàn)A、B用于修飾bean類和其類成員;C主要用于取出bean類的數(shù)據(jù)并將其作xml綁定,代碼中使用了E作為測試類;E中可能包含著多個D.
在了解了這個簡單框架后,我們來看一下BRFW的代碼吧!
4.BRFW源代碼分析:
A.Persistent類:
清單1:
package com.bjinfotech.practice.annotation.runtimeframework;
import java.lang.annotation.*;
/**
* 用于修飾類的固有類型成員變量的annotation
* @author cleverpig
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Persistent {
String value() default "";
}
B.Exportable類:
清單2:
package com.bjinfotech.practice.annotation.runtimeframework;
import java.lang.annotation.*;
/**
* 用于修飾類的類型的annotation
* @author cleverpig
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Exportable {
//名稱
String name() default "";
//描述
String description() default "";
//省略name和description后,用來保存name值
String value() default "";
}
C.AddressForTest類:
清單3:
package com.bjinfotech.practice.annotation.runtimeframework;
/**
* 用于測試的地址類
* @author cleverpig
*
*/
@Exportable("address")
public class AddressForTest {
//國家
@Persistent
private String country=null;
//省級
@Persistent
private String province=null;
//城市
@Persistent
private String city=null;
//街道
@Persistent
private String street=null;
//門牌
@Persistent
private String doorplate=null;
public AddressForTest(String country,String province,
String city,String street,String doorplate){
this.country=country;
this.province=province;
this.city=city;
this.street=street;
this.doorplate=doorplate;
}
}
D.AddressListForTest類:
清單4:
package com.bjinfotech.practice.annotation.runtimeframework;
import java.util.*;
/**
* 友人通訊錄
* 包含:姓名、年齡、電話、住址(多個)、備注
* @author cleverpig
*
*/
@Exportable(name="addresslist",description="address list")
public class AddressListForTest {
//友人姓名
@Persistent
private String friendName=null;
//友人年齡
@Persistent
private int age=0;
//友人電話
@Persistent
private ArrayList
//友人住址:家庭、單位
@Persistent
private ArrayList
//備注
@Persistent
private String note=null;
public AddressListForTest(String name,int age,
ArrayList
ArrayList
String note){
this.friendName=name;
this.age=age;
this.telephone=new ArrayList
this.AddressForText=new ArrayList
this.note=note;
}
}
E.ExportToXml類:
清單5:
package com.bjinfotech.practice.annotation.runtimeframework;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.ArrayList;
/**
* 將具有Exportable Annotation的對象轉換為xml格式文本
* @author cleverpig
*
*/
public class ExportToXml {
/**
* 返回對象的成員變量的值(字符串類型)
* @param field 對象的成員變量
* @param fieldTypeClass 對象的類型
* @param obj 對象
* @return 對象的成員變量的值(字符串類型)
*/
private String getFieldValue(Field field,Class fieldTypeClass,Object obj){
String value=null;
try{
if (fieldTypeClass==String.class){
value=(String)field.get(obj);
}
else if (fieldTypeClass==int.class){
value=Integer.toString(field.getInt(obj));
}
else if (fieldTypeClass==long.class){
value=Long.toString(field.getLong(obj));
}
else if (fieldTypeClass==short.class){
value=Short.toString(field.getShort(obj));
}
else if (fieldTypeClass==float.class){
value=Float.toString(field.getFloat(obj));
}
else if (fieldTypeClass==double.class){
value=Double.toString(field.getDouble(obj));
}
else if (fieldTypeClass==byte.class){
value=Byte.toString(field.getByte(obj));
}
else if (fieldTypeClass==char.class){
value=Character.toString(field.getChar(obj));
}
else if (fieldTypeClass==boolean.class){
value=Boolean.toString(field.getBoolean(obj));
}
}
catch(Exception ex){
ex.printStackTrace();
value=null;
}
return value;
}
/**
* 輸出對象的字段,當對象的字段為Collection或者Map類型時,要調(diào)用exportObject方法繼續(xù)處理
* @param obj 被處理的對象
* @throws Exception
*/
public void exportFields(Object obj) throws Exception{
Exportable exportable=obj.getClass().getAnnotation(Exportable.class);
if (exportable!=null){
if (exportable.value().length()>0){
// System.out.println("Class annotation Name:"+exportable.value());
}
else{
// System.out.println("Class annotation Name:"+exportable.name());
}
}
else{
// System.out.println(obj.getClass()+"類不是使用Exportable標注過的");
}
//取出對象的成員變量
Field[] fields=obj.getClass().getDeclaredFields();
for(Field field:fields){
//獲得成員變量的標注
Persistent fieldAnnotation=field.getAnnotation(Persistent.class);
if (fieldAnnotation==null){
continue;
}
//重要:避免java虛擬機檢查對私有成員的訪問權限
field.setAccessible(true);
Class typeClass=field.getType();
String name=field.getName();
String value=getFieldValue(field,typeClass,obj);
//如果獲得成員變量的值,則輸出
if (value!=null){
System.out.println(getIndent()+"<"+name+">\n"
+getIndent()+"\t"+value+"\n"+getIndent()+""+name+">");
}
//處理成員變量中類型為Collection或Map
else if ((field.get(obj) instanceof Collection)||
(field.get(obj) instanceof Map)){
exportObject(field.get(obj));
}
else{
exportObject(field.get(obj));
}
}
}
//縮進深度
int levelDepth=0;
//防止循環(huán)引用的檢查者,循環(huán)引用現(xiàn)象如:a包含b,而b又包含a
CollectioncyclicChecker=new ArrayList