Annotation不算經常使用的技術,早前用它寫了一些玩意兒,過了一年又忘乾淨了,今天寫點東西記下來,以備再忘之需。java
java.lang.annotation,接口 Annotation。對於Annotation,是Java5的新特性,JDK5引入了Metedata(元數據)很容易的就可以調用Annotations。Annotations提供一些原本不屬於程序的數據,好比:一段代碼的做者或者告訴編譯器禁止一些特殊的錯誤。An annotation 對代碼的執行沒有什麼影響。Annotations使用@annotation的形式應用於代碼:類(class),屬性(attribute),方法(method)等等。一個Annotation出如今上面提到的開始位置,並且通常只有一行,也能夠包含有任意的參數。數組
——————百度百科dom
Annotation是什麼,上面說得很清楚了,下面重點說,它怎麼寫,和有什麼用。ide
1、Annotation的基本寫法this
/** * @author caiyu * @date 2014-1-21 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSchemaConfig { String type() default "get";
String value();
}
一、DataSchemaConfig爲Annotation的名稱spa
二、 @Retention 表示該Annotation的保留級別code
分別如下三種:htm
RetentionPolicy.RUNTIMEblog
會記錄在CLASS裏,同時會在運行時保留該註解,以使其能夠被反射讀取。接口
RetentionPolicy.SOURCE
只存在於源碼裏,會被編譯器拋棄
RetentionPolicy.CLASS
會被編譯器記錄在CLASS文件中,但虛擬機不會在運行時保留它。該選項是默認選項
三、@Target表示該Annotation的影響範圍,以下所示:
package java.lang.annotation; /** * A program element type. The constants of this enumerated type * provide a simple classification of the declared elements in a * Java program. * * <p>These constants are used with the {@link Target} meta-annotation type * to specify where it is legal to use an annotation type. * * @author Joshua Bloch * @since 1.5 */ public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE }
四、內容組織形式
String type() default "get";
這段聲明裏,String爲成員類型,type爲成員名稱(必須寫上括號),default "get"表示缺省指爲"get"
五、使用見以下示例代碼
/** * @author caiyu * @date 2014-1-22 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface DataType { public String value() default "map"; } @DataType(value = "bean") public class MapModel { private Map<String, Object> o = new HashMap<String, Object>(); @GET public Object get(String key) { return o.get(key); } @PUT public void put(String key, Object value) { o.put(key, value); } }
DataType 這個Annotation被聲明爲Runtime以及TYPE,因此它能夠被用於註解MapModel這個類。
括號裏的value="bean",則是爲其value賦值1,同時因爲value是個特殊成員,能夠寫做
@DataType("bean")
若是寫做
@DataType
則value會使用默認值"map"
六、數組形式的成員類型的使用
把上面的內容改爲下面的格式:
String[] value() default "map";
以前的這種寫法@DataType("bean")仍然是合法的
同時能夠寫做@DataType({"map","bean"})
2、Annotaion的用途
在介紹@Retention的時候,其實已經說明了Annotation的三種類型了,SOURCE和CLASS類型使用不多,若是你不是須要本身寫一個Java Compiler或者Editor,基本用不上。
這裏重點說說RUNTIME類型。
咱們知道,RUNTIME會被保存在CLASS文件中,並且其中記錄的信息能夠經過反射來獲取到,因而能夠利用這點實現一些方便的配置(好比Spring和Hibernate就是利用這點)。
來看看一個MapModel類:
@DataType public class MapModel { private Map<String, Object> o = new HashMap<String, Object>(); @get public Object getProperty(String key) { return o.get(key); } @put public void putProperty(String key, Object value) { o.put(key, value); } public String toString() { return o.toString(); } }
能夠看到,MapModel標記了三個註解,分別是DataType和get、put
下面的代碼,是用來把該Model和org.dom4j.Element相互轉換的,注意只能參考,並不完整:
/** * 序列化註解類型 * * @param content * @param schema * @return */ private Element serialMapType(Object content, IDataSchema<?> schema) { DataType type = schema.getType().getAnnotation(DataType.class); if (type != null && type.value() == DataTypeValue.MAP) { Element root = DocumentFactory.getInstance().createElement( schema.getName()); Method getMethod = extraMethodByAnnotation(schema.getType(), get.class); if (getMethod == null) throw new InvalidAnnotationConfigException( "Invalid annotation class: " + schema.getType().getName()); try { for (Entry<String, IDataSchema<?>> field : schema .getFieldEntrySet()) { Object o = getMethod.invoke(content, field.getValue() .getId()); Element e = save(o, field.getValue()); root.add(e); } return root; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { throw new InvalidAnnotationConfigException( "Invalid put method : " + getMethod.getName()); } catch (InvocationTargetException e) { e.printStackTrace(); } } return null; } /** * 反序列化註解類型數據 * * @param persistentTarget * @param schema * @return */ private Object deserialMapType(Element persistentTarget, IDataSchema<?> schema) { Object instance = null; DataType type = schema.getType().getAnnotation(DataType.class); if (type != null && type.value() == DataTypeValue.MAP) { Method putMethod = extraMethodByAnnotation(schema.getType(), put.class); if (putMethod == null) throw new InvalidAnnotationConfigException( "Invalid annotation class: " + schema.getType().getName()); try { instance = schema.getType().newInstance(); for (Entry<String, IDataSchema<?>> field : schema .getFieldEntrySet()) { Element e = persistentTarget.element(field.getValue() .getName()); Object v = load(e, field.getValue()); putMethod.invoke(instance, new Object[] { field.getValue().getId(), v }); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { throw new InvalidAnnotationConfigException( "Invalid put method : " + putMethod.getName()); } catch (InvocationTargetException e) { e.printStackTrace(); } } return instance; }
/** * 抽取含有指定註解的方法 * * @param type * @param annotationClass * @return */ private Method extraMethodByAnnotation(Class<?> type, Class<? extends Annotation> annotationClass) { for (Method method : type.getDeclaredMethods()) { Annotation t = method.getAnnotation(annotationClass); if (t != null) { return method; } } return null; }