Java学习:Annotation注解

时间:2022-10-06 15:38:31

Annotation不算常用的技术,早前用它写了一些玩意儿,过了一年又忘干净了,今天写点东西记下来,以备再忘之需。

 

java.lang.annotation,接口 Annotation。对于Annotation,是Java5的新特性,JDK5引入了Metedata(元数据)很容易的就能够调用Annotations。Annotations提供一些本来不属于程序的数据,比如:一段代码的作者或者告诉编译器禁止一些特殊的错误。An annotation 对代码的执行没有什么影响。Annotations使用@annotation的形式应用于代码:类(class),属性(attribute),方法(method)等等。一个Annotation出现在上面提到的开始位置,而且一般只有一行,也可以包含有任意的参数。

 

——————百度百科

 

Annotation是什么,上面说得很清楚了,下面重点说,它怎么写,和有什么用。

 一、Annotation的基本写法

/**
*
@author caiyu
* @date 2014-1-21
*/

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSchemaConfig {
String type()
default "get";
    String value();
}

 

1、DataSchemaConfig为Annotation的名称

2、 @Retention 表示该Annotation的保留级别

分别以下三种:

RetentionPolicy.RUNTIME

会记录在CLASS里,同时会在运行时保留该注解,以使其可以被反射读取。

RetentionPolicy.SOURCE

只存在于源码里,会被编译器抛弃

RetentionPolicy.CLASS

会被编译器记录在CLASS文件中,但虚拟机不会在运行时保留它。该选项是默认选项

3、@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
}

 

4、内容组织形式

String type() default "get";

 这段声明里,String为成员类型,type为成员名称(必须写上括号),default "get"表示缺省指为"get"

 

5、使用见如下示例代码

  

/**
*
@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"

 

6、数组形式的成员类型的使用

 把上面的内容改成下面的格式:

String[] value() default "map";

之前的这种写法@DataType("bean")仍然是合法的

  同时可以写作@DataType({"map","bean"})

 

 

 二、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;
}