preface
Annotations are labels that are inserted into the source file. Javac will generate the same bytecode for the code with or without annotations. If you want to use annotations, you must provide annotation processing tools. These tools can process annotations at run time (reflection), at compile time (language model) or at bytecode level (bytecode Engineering). This article will only describe the tools for processing annotations at compile time, that is, language model and annotation processor. If you want to use annotation processor, you must understand language model API and compiler API. The above concepts mentioned in this article are recorded in detail in other articles of the author, which can be consulted if you are interested.
annotation
Annotation interface
All annotations are defined through the annotation interface, and all annotation interfaces are implicitly extended from Java lang.annotation. Annotation interface. The annotation interface does not support inheritance and does not support circular dependency (annotation B cannot use annotation A if it uses itself or annotation A uses annotation b).
modifiers @interface AnnotationName{ type elementName1(); type elementName2() default value; }
All annotations are used in the following forms. If the annotation element has a default value, it can be used without specifying a value for the element.
@AnnotationName(elementName1=value1,eementName2=value2)
Annotation element
All elements defined in the annotation interface are called annotation elements. Annotation elements must be of the following types:
- Basic type
- String
- Class
- enum
- Annotation
- An array of the above types
Default value
The value of the annotation element cannot be null. You can use default to specify a default value for the annotation element:
@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 {}; }
The default value is not stored with the annotation, but obtained dynamically. If you modify the default value of the annotation, the new default value will also be used in the compiled class file.
marker annotation
If there are no elements in an annotation or all elements have default values, this annotation is called tag annotation, which can be used without parentheses.
@AnnotationName
Single value annotation
If an element named value is defined in the annotation and value is the only element that needs to be assigned when using the annotation, the value of value can be given directly in parentheses.
@AnnotationName(value)
Meta annotation
Meta annotations are annotations for annotations.
@Target
@Target is used to limit where the current annotation can be used. An annotation not constrained by @ target can be used anywhere.
public @interface Target { ElementType[] value(); }
Attribute value | explain |
---|---|
ANNOTATION_TYPE | Can be used in annotations |
CONSTRUCTOR | Can be used on constructors |
FIELD | Can be used on fields |
LOCAL_VARIABLE | Can be used on local variables |
METHOD | It can be used in methods |
PACKAGE | It can be used on bags |
PARAMETER | Can be used on method parameters |
TYPE | Can be used on classes and interfaces |
TYPE_PARAMETER | Can be used on generic parameters |
TYPE_USE | Type usage |
When an annotation is used on a local variable, it can only be processed at run time. It should be that the class file does not record the local variable information.
@Retention
@Retention is used to specify how long an annotation should be retained. The default value is CLASS.
public @interface Retention { RetentionPolicy value(); }
Attribute value | explain |
---|---|
SOURCE | Keep until compilation |
CLASS | Keep until run |
RUNTIME | Keep after running |
@Documented
@Documented is used to prompt the archiving tool whether to include this annotation when archiving.
public @interface Documented { }
@Inherited
@Inherited can only be applied to the annotation annotated by @ Target(ElementType.TYPE). The function of this annotation is to allow subclasses to inherit the annotation annotated by this annotation when inheriting the parent class of the annotation annotated by this annotation.
public @interface Inherited { }
@Repeatable
@Repeatable is used to specify that the current annotation can be used multiple times in the same place.
public @interface Repeatable { Class<? extends Annotation> value(); }
Its value element specifies a container annotation of the current annotation, and the storage time of this container annotation must be greater than or equal to the sub annotation:
@Repeatable(MyAnnotations.class) @interface MyAnnotation{ } @interface MyAnnotations{ MyAnnotation[] value(); }
annotation processor
Processor represents the interface of the annotation processor. The annotation processor can process annotations at compile time. Because the annotation processing function is integrated into Javac, the annotation processor can be called to process annotations at compile time through the following commands:
javac -processor <processorClassNames> <src>
The compiler locates the annotations in the source file, and each annotation processor executes them in turn to get the annotations they are interested in. The annotation processor can only create source files and cannot modify existing source files. If an annotation processor creates a new source file, the above process will be repeated. If a cycle does not produce any new source files, all source files will be compiled.
void init(ProcessingEnvironment processingEnv)//This method will be called by the annotation processing tool and enter the processingenvironment parameter. boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)//The method that actually handles annotations returns true after all processing is completed Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) Set<String> getSupportedAnnotationTypes()//Specifies the annotations that the annotation processor can process Set<String> getSupportedOptions()//Specifies the options supported by the annotation processor. Each string returned in the collection must be a sequence of identifiers separated by periods. SourceVersion getSupportedSourceVersion()//Specifies the Java version of the source code
The last three methods above can be replaced by the following three annotations:
annotation |
---|
@SupportedAnnotationTypes |
@SupportedOptions |
@SupportedSourceVersion |
When the bedstead annotation processor, it usually inherits the AbstractProcessor class.
RoundEnvironment
The annotation processing framework provides an object that implements the interface for the annotation handler, so that the handler can query information about a round of annotation processing.
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
Processingenvironment provides many useful tool classes Elements, Types and Filer. So that handlers can use tools to write new files, report error messages, and find other utilities.
Elements getElementUtils() Filer getFiler() Types getTypeUtils() Locale getLocale() Messager getMessager() Map<String,String> getOptions() SourceVersion getSourceVersion()
Filer
Filer supports the annotation processor to create new files. Three kinds of files can be distinguished: source file, class file and auxiliary resource file.
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
The Messager provides a way for the annotation processor to report error messages, warnings, and other notifications.
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 indicates the annotation of the annotation.
String getMessage() String getValue()
Completions
Tool class used to encapsulate the Completion object.
static Completion of(String value) static Completion of(String value, String message)
demo
The code address is as follows:
https://github.com/chinesecooly/annotation-processor.git