0
点赞
收藏
分享

微信扫一扫

Java注解和注解处理器详解

文章目录

前言

注解是指一些被插入到源文件的标签。Javac对于包含注解或不包含注解的代码会产生相同的字节码,要想使用注解必须提供注解处理工具,这些工具可以在运行时对注解进行处理(反射)、在编译时对注解进行处理(语言模型)或者在字节码层面对注解进行处理(字节码工程)。本文只会描述在编译时对注解进行处理的工具,也就是语言模型和注解处理器,要想使用注解处理器必须了解语言模型API及编译器API。以上本文提及的概念在作者其它文章中都有详细记载,感兴趣可查阅。

注解

注解接口

所有注解都通过注解接口定义,所有注解接口都隐式扩展自java.lang.annotation.Annotation接口。注解接口不支持继承,并且不支持循环依赖(自身使用自身或者注解A使用了注解B,那么注解B就不能使用注解A)。

modifiers @interface AnnotationName{
	type elementName1();
	type elementName2() default value;
} 

所有注解通过以下形式使用,如果注解元素有默认值,在使用时可以不用为该元素指定值。

@AnnotationName(elementName1=value1,eementName2=value2)

注解元素

所有在注解接口中定义的元素称为注解元素,注解元素必须是以下类型:

  • 基本类型
  • String
  • Class
  • enum
  • Annotation
  • 以上类型组成的数组

默认值

注解元素的值不能为null,可以使用default为注解元素指定一个默认值:

@interface myAnnotaton{
    int intElement() default 1;
    String stringElement() default "value";
    Class classElement() default String.class;
    StandardOpenOption enumElement() default StandardOpenOption.CREATE;
    NotNull annotationElement() default @NotNull;
    int[] arrayElement()default {};
}

默认值并不和注解存储在一起,而是动态获取的,如果修改注解的默认值,那么已经编译过的类文件中也会使用这个新的默认值。

标记注解

如果一个注解中没有任何元素或者所有元素都有默认值,那么这种注解称为标记注解,在使用时可以不用加括号。

@AnnotationName

单值注解

如果在注解中定义了名为 value 的元素,并且在使用该注解时,value为唯一一个需要赋值的元素,那么可以直接在括号中给出value的值。

@AnnotationName(value)

元注解

元注解是用于注解注解的注解。

@Target

@Target用于限制当前注解可以用在哪些地方,一个没有被@Target约束的注解可以用在任何地方。

public @interface Target {
    ElementType[] value();
}
属性值说明
ANNOTATION_TYPE可以用在注解上
CONSTRUCTOR可以用在构造器上
FIELD可以用在字段上
LOCAL_VARIABLE可以用在局部变量上
METHOD可以用在方法上
PACKAGE可以用在包上
PARAMETER可以用在方法参数上
TYPE可以用在类和接口上
TYPE_PARAMETER可以用在泛型参数上
TYPE_USE类型用法

当一个注解被用在局部变量上时只能在运行时处理注解,应为类文件不记录局部变量信息。

@Retention

@Retention用于指定一条注解应该保留多长时间,默认值是CLASS

public @interface Retention {
    RetentionPolicy value();
}
属性值说明
SOURCE保留到编译之前
CLASS保留到运行之前
RUNTIME保留到运行之后

@Documented

@Documented用于提示归档工具在归档时是否包含此注解。

public @interface Documented {
}

@Inherited

@Inherited只能应用于被@Target(ElementType.TYPE)注解的注解,该注解的作用是允许子类继承被该注解注解的注解注解的父类时继承被该注解注解的注解。

public @interface Inherited {
}

@Repeatable

@Repeatable用于指定当前注解可以在同一地方使用多次。

public @interface Repeatable {
    Class<? extends Annotation> value();
}

它的value元素指定当前注解的一个容器注解,并且此容器注解的保存时间必须大于等于子注解:

@Repeatable(MyAnnotations.class)
@interface MyAnnotation{   
}

@interface MyAnnotations{
    MyAnnotation[] value();
}

注解处理器

在这里插入图片描述
Processor代表注解处理器的接口,注解处理器可以在编译时处理注解,因为注解处理功能被集成到了Javac中,通过以下命令就可以在编译时调用注解处理器处理注解:

javac -processor <processorClassNames> <src>

编译器会定位源文件中的注解,每个注解处理器都会依次执行,并得到它们感兴趣的注解。注解处理器只能创建源文件,不能在已有源文件上进行修改。如果一个注解处理器创建了一个新的源文件,那么上述过程就会重复执行,如果某次循环没有再产生任何新的源文件,那么就编译所有源文件。

void init(ProcessingEnvironment processingEnv)//该方法会被注解处理工具调用,并输入ProcessingEnviroment参数。
boolean	process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)//真正处理注解的方法,全部处理完成返回true
Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText)
Set<String>	getSupportedAnnotationTypes()//指定注解处理器可以处理的注解
Set<String>	getSupportedOptions()//指定注解处理器支持的选项,集合中返回的每个字符串必须是一个以句号分隔的标识符序列。
SourceVersion getSupportedSourceVersion()//指定源代码的Java版本

上文最后三个方法可以使用以下三个注解代替:

注解
@SupportedAnnotationTypes
@SupportedOptions
@SupportedSourceVersion

在床架注解处理器时,通常继承AbstractProcessor类。

RoundEnvironment

注解处理框架为注释处理程序提供一个实现该接口的对象,以便处理程序可以查询关于一轮注解处理的信息。

boolean	errorRaised()
Set<? extends Element>	getElementsAnnotatedWith(Class<? extends Annotation> a)
Set<? extends Element>	getElementsAnnotatedWith(TypeElement a)
Returns the elements annotated with the given annotation type.
Set<? extends Element>	getRootElements()
boolean	processingOver()

ProcessingEnvironment

ProcessingEnviroment提供很多有用的工具类Elements, Types和Filer。以便处理程序可以使用工具来编写新文件、报告错误消息和查找其它实用程序。

Elements getElementUtils()
Filer getFiler()
Types getTypeUtils()
Locale getLocale()
Messager getMessager()
Map<String,String> getOptions()
SourceVersion getSourceVersion()

Filer

Filer支持注释处理器创建新文件。可以区分三种文件:源文件、类文件和辅助资源文件。

JavaFileObject	createClassFile(CharSequence name, Element... originatingElements)
FileObject	createResource(JavaFileManager.Location location, CharSequence pkg, CharSequence relativeName, Element... originatingElements)
JavaFileObject	createSourceFile(CharSequence name, Element... originatingElements)
FileObject	getResource(JavaFileManager.Location location, CharSequence pkg, CharSequence relativeName)

Messager

Messager提供了注解处理器报告错误消息、警告和其他通知的方式。

void printMessage(Diagnostic.Kind kind, CharSequence msg)
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e)
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a)
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v)

Completion

Completion表示注解的注释。

String	getMessage()
String	getValue()

Completions

用于封装Completion对象的工具类。

static Completion of(String value)
static Completion of(String value, String message)

demo

代码地址如下:

https://github.com/chinesecooly/annotation-processor.git
举报

相关推荐

0 条评论