Java 之 Annotation
来源:互联网 发布:网络杀手是什么意思啊 编辑:程序博客网 时间:2024/06/13 20:44
Annotation 是 Java 5.0 开始引入的新特征。注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
1、元注解
元注解是指注解的注解,包括 @Retention @Target @Document @Inherited 四种。
1.1、@Retention
定义注解的保留策略,指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。
@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.RUNTIME)
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * 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. */ CLASS, /** * 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. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME}
1.2、@Target
定义注解的作用目标,指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在Target元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。
@Target(ElementType.TYPE)
@Target(ElementType.FIELD)
@Target(ElementType.METHOD)
@Target(ElementType.PARAMETER)
@Target(ElementType.CONSTRUCTOR)
@Target(ElementType.LOCAL_VARIABLE)
@Target(ElementType.ANNOTATION_TYPE)
@Target(ElementType.PACKAGE)
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}
1.3、@Document
说明该注解将被包含在JavaDoc中
1.4、@Inherited
说明子类可以继承父类中的该注解,默认情况下注解并不会被继承到子类中,可以在自定义注解时加上@Inherited注解声明使用继承。
2、自定义注解
2.1. 定义注解
2.1.1 @Handler
import java.lang.annotation.*;@Inherited@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Handler{ String[] value() default {};}
2.1.2 @SetHandler
import java.lang.annotation.*;@Inherited@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface SetHandler{}
2.1.3 @GetHandler
import java.lang.annotation.*;@Inherited@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface GetHandler{}
2.2. 使用注解
import java.util.*;@Handler("HandlerMethod")public class HandlerTest{ public int setHandler(String method, HashMap<String, String> properties) { return 0; } @SetHandler public int setHandler(String method, Map<String, String> properties) { return 0; } @GetHandler public String getHandler(String method, Map<String, String> properties) { return null; }}
2.3. 处理注解
import java.lang.reflect.*;import java.util.*;public class Main{ public static void main(String[] args) throws Exception { Map<String, String> prop = new HashMap<String, String>(); prop.put("0", "Property0"); prop.put("1", "Property0"); Class clazz = loadClass("HandlerTest"); doHandler(clazz, "Good luck !!!", prop); } // load class by name and find annotation private static Class loadClass(String name) throws ClassNotFoundException { Class clazz = Class.forName(name); if (clazz.isAnnotationPresent(Handler.class)) { Handler handler = (Handler) clazz.getAnnotation(Handler.class); System.out.println("!!! " + clazz + " for " + Arrays.toString(handler.value())); } return clazz; } // find annotated method and perform private static void doHandler(Class clazz, String arg, Map<String, String> prop) throws IllegalAccessException, InstantiationException { Object object = clazz.newInstance(); for (Method method : clazz.getMethods()) { if (method.isAnnotationPresent(SetHandler.class)) { invoke(object, method, arg, prop); } else if (method.isAnnotationPresent(GetHandler.class)) { invoke(object, method, arg, prop); } } } // invoke method private static Object invoke(Object object, Method method, String arg, Map<String, String> properties) { Class<?>[] type = method.getParameterTypes(); Map<String, String> prop = null; Class clazz0 = type[1]; Object retval = null; if (properties != null) { Class clazz1 = properties.getClass(); if (clazz0 == clazz1) { System.out.println("!!! " + clazz0 + " == " + clazz1); } else if (clazz1.isAssignableFrom(clazz0)) { System.out.println("!!! " + clazz0 + " <= " + clazz1); } else if (clazz0.isAssignableFrom(clazz1)) { System.out.println("!!! " + clazz0 + " => " + clazz1); } else { System.out.println("!!! " + clazz0 + " != " + clazz1); } try { if (clazz0.isAssignableFrom(clazz1)) { prop = (Map<String, String>) clazz1.newInstance(); } else { prop = (Map<String, String>) clazz0.newInstance(); } } catch (Exception e) { e.printStackTrace(); } if (prop != null) { for (Map.Entry<String, String> entry : properties.entrySet()) { prop.put(entry.getKey(), entry.getValue()); } } } try { retval = method.invoke(object, new Object[]{arg, prop}); } catch (Exception e) { e.printStackTrace(); } return retval; }}
3. 注解处理器
如上面的例子中 @SetHandler 和 @GetHandler 被用来注解方法,但是怎么样来保证被注解的方法有一个统一的声明原型呢。这里可以让Java的编译器来帮忙在编译阶段检查被注解的方法的原型,需要客制化一个注解处理器的插件来让Java编译器处理。为Java的编译器写插件就需要将注解处理器继承自 javax.annotation.processing.AbstractProcessor 且实现一些必要的方法来让其协同工作。怎么样让编译器找到和使用插件呢?这里必须提供一个jar文件,将注解处理器打包在此jar中,并且还需要打包一个特定的文件 javax.annotation.processing.Processor 到 META-INF/services 路径下,其内容是注解处理器的合法的全名列表。
import javax.annotation.processing.*;import javax.lang.model.SourceVersion;import javax.lang.model.element.*;import javax.lang.model.type.*;import java.util.*;public class MyProcessor extends AbstractProcessor{ private static final String OBJ_TYPE = "java.lang.Object"; private static final String STR_TYPE = "java.lang.String"; private static final String MAP_TYPE = "java.util.Map<?,?>"; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); } @Override public Set<String> getSupportedAnnotationTypes() { Set<String> types = new LinkedHashSet<String>(); types.add(SetHandler.class.getCanonicalName()); types.add(GetHandler.class.getCanonicalName()); return types; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (TypeElement annotation : annotations) { for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) { TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); if (!(element instanceof ExecutableElement) || element.getKind() != ElementKind.METHOD) { error(element, "@%s.%s annotation must be on a method.", enclosingElement.getQualifiedName(), element.toString()); return false; } Set<Modifier> modifiers = element.getModifiers(); if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC) || modifiers.contains(Modifier.PROTECTED)) { error(element, "@%s.%s method must not be protected, private or static.", enclosingElement.getQualifiedName(), element.toString()); return false; } ExecutableElement executableElement = (ExecutableElement) element; List<? extends VariableElement> parameters = executableElement.getParameters(); if (parameters.size() != 2) { error(element, "@%s.%s methods must have 2 parameters.", enclosingElement.getQualifiedName(), element.toString()); return false; } VariableElement parameter0 = parameters.get(0); TypeMirror typeMirror0 = parameter0.asType(); if (!isSubtypeOfType(typeMirror0, STR_TYPE)) { error(element, "The 1st parameter of methods @%s.%s must be 'String'.", enclosingElement.getQualifiedName(), element.toString()); return false; } VariableElement parameter1 = parameters.get(1); TypeMirror typeMirror1 = parameter1.asType(); if (!isSubtypeOfType(typeMirror1, MAP_TYPE, STR_TYPE, STR_TYPE)) { error(element, "The 2nd parameter of methods @%s.%s should assignable from 'Map<String, String>'.", enclosingElement.getQualifiedName(), element.toString()); return false; } } } for (Element element : roundEnv.getElementsAnnotatedWith(SetHandler.class)) { TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); ExecutableElement executableElement = (ExecutableElement) element; TypeMirror returnType = executableElement.getReturnType(); if (!isSubtypeOfType(returnType, "int")) { error(element, "@%s.%s methods must have a 'int' return type.", enclosingElement.getQualifiedName(), element.toString()); return false; } } for (Element element : roundEnv.getElementsAnnotatedWith(GetHandler.class)) { TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); ExecutableElement executableElement = (ExecutableElement) element; TypeMirror returnType = executableElement.getReturnType(); if (!isSubtypeOfType(returnType, OBJ_TYPE)) { error(element, "@%s.%s methods should have a 'Object' return type.", enclosingElement.getQualifiedName(), element.toString()); return false; } } return true; } private boolean isSubtypeOfType(TypeMirror typeMirror, String otherType, String... genericTypes) { if (otherType.equals(typeMirror.toString())) { return true; } if (typeMirror.getKind() != TypeKind.DECLARED) { return false; } DeclaredType declaredType = (DeclaredType) typeMirror; List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments(); if (typeArguments.size() > 0) { StringBuilder typeString = new StringBuilder(declaredType.asElement().toString()); typeString.append('<'); for (int i = 0; i < typeArguments.size(); i++) { if (i > 0) { typeString.append(','); } typeString.append('?'); if (genericTypes != null && genericTypes.length > i) { if (!isSubtypeOfType(typeArguments.get(i), genericTypes[i])) { return false; } } } typeString.append('>'); if (typeString.toString().equals(otherType)) { return true; } } Element element = declaredType.asElement(); if (!(element instanceof TypeElement)) { return false; } TypeElement typeElement = (TypeElement) element; TypeMirror superType = typeElement.getSuperclass(); if (isSubtypeOfType(superType, otherType)) { return true; } for (TypeMirror interfaceType : typeElement.getInterfaces()) { if (isSubtypeOfType(interfaceType, otherType)) { return true; } } return false; } private void error(Element element, String message, Object... args) { if (args.length > 0) { message = String.format(message, args); } processingEnv.getMessager().printMessage(javax.tools.Diagnostic.Kind.ERROR, message, element); }}
4. 注解应用实例
- butterknife
- java学习之annotation
- Java之自定义Annotation
- java 之annotation
- JAVA之Annotation(注释)
- Java 之 Annotation
- Java之------注解 ( Annotation )
- Java之Annotation学习
- java之Annotation
- java基础之Annotation
- Java之Annotation(注解)
- Java之Annotation
- Java高新技术之Annotation(注解)
- Java 之 Annotation(注解)介绍
- Java基础之理解Annotation
- Java基础之理解Annotation
- Java基础之理解Annotation
- Java注解之Annotation详解
- Java基础之理解Annotation
- HDU 1166 敌兵布阵
- ps在psd格式图片里面切图流程
- listview使用ArrayAdapter显示文字
- mssql数据库导出表明字段名和说明到Excel
- C#之委托学习三
- Java 之 Annotation
- Android购物车全选功能实现·
- XML解析的三种方式
- opencv学习---运动目标(前景)检测
- 怎么将pdf转换成word 批量转换怎么转
- 使用PHPExcel 时报错ZipArchive::getFromName(): Invalid or uninitialized Zip object
- Android字符串相关类 - String
- 就是这么简单!使用Rest-assured 测试Restful Web Services
- Javamail实现邮件发送