当前位置:网站首页>Definition of annotations and annotation compiler
Definition of annotations and annotation compiler
2022-06-21 09:34:00 【tragically unhappy】
annotation
annotation ( Also known as metadata ) It provides a formal way for us to add information to our code , Make it easier for us to use this data at a later time .
Annotations are, to some extent, a combination of metadata and source code files , Instead of saving in an external document .
The note is Java 5 Introduced , It provides Java You can't express it, but you need to completely express the additional information required by the program . This information is verified in a compiler verified format . Annotations can generate descriptor files , Even new class definitions , And help to reduce writing “ Model ” The burden of code .
By using annotations , You can save metadata in Java In the source code , And has the following advantages : Easy to read code , Compiler type checking , Use Annotation API Construct processing tools for your own annotations . Even if Java Defines some types of metadata , But in general, the addition of annotation types and how to use them are entirely up to you .
Annotation is the concept of a real language level , Constructed to enjoy compiler type check protection . Annotations save all information at the source level, not through annotation text , This makes the code simpler and easier to maintain .
The syntax of annotations is very simple , It is mainly to add... To the existing syntax @ Symbol ,Java 5 The first three definitions are quoted in java.lang Comments in the package :
- @Override: Indicates that the current method definition will override the method of the base class .
- @Deprecated: If you use this annotation element to be called , The compiler will issue a warning message .
- @SuppressWarnings: Turn off improper compiler warnings .
- @SafeVarargs: stay Java 7 Used to prohibit having generics on varargs The method of a parameter or the calling method of a constructor warns .
- @FunctionalInterface:Java 8 Add a function interface to indicate that the type is declared as a functional interface .
besides , also 5 Additional annotation types are used to create new annotations . The following will describe .
Whenever you create a class or interface that involves repetitive work , You can usually use annotations to automate and simplify the process . For example, in Enterprise JavaBean(EJB) Much of the extra work in is eliminated by annotations .
1. Basic grammar
1.1 Definition notes
The following is the definition of an annotation . It and other Java As the interface , It will also be compiled into class file .
@Target(ElementType.METHOD)// Where the defined annotation can be applied ( For example, method or field )
@Retention(RetentionPolicy.RUNTIME)// Defines where annotations are available , In the source code (SOURCE),class file (CLASS) Or the runtime (RUNTIME)
public @interface Test {
}
except @ Outside the symbol ,@Test The definition of is more like an empty interface . The definition of annotations requires some meta annotations (meta-annotation), such as @Target and Retention.
Annotations usually contain elements that represent specific values . When the analysis deals with annotations , Programs or tools can use these values . The annotated element looks like an interface method , But you can specify an initial value for it .
Annotations that do not contain any elements are markup annotations (marker annotation), As in the above example @Test.
Here is a simple comment , We can use it to track use cases in projects .
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
int id();
// If a method is annotated without description Value , The processor of the annotation will use the default value of this element
String description() default "no description";
}
The programmer can use this annotation to annotate a method or a set of methods that satisfy a particular use case . therefore , The project manager can control the progress of the project by counting the use cases that have implemented this annotation , While maintaining the project, developers can easily find use cases to update or debug the business logic in the system .
id and description Similar to method definition . Because the compiler will be right id Type checking is therefore a reliable way to associate the tracking database with use case documents and source code .
In the following classes , Three methods are annotated as use cases :
public class PasswordUtils {
@UseCase(id = 47,description = "Password must contain at least one numeric")
public boolean validatePassword(String passwd) {
return (passwd.matches("\\w*\\d\\w"));
}
@UseCase(id = 48)
public String encryptPassword(String passwd) {
return new StringBuilder(passwd).reverse().toString();
}
@UseCase(id = 49, description = "New password can't equal previously used ones")
public boolean checkForNewPassword(List<String> prePasswords,String passwd) {
return !prePasswords.contains(passwd);
}
}
The annotated elements are represented as name - value On the form of , And need to be placed in @UseCase In parentheses after the declaration .
1.2 Yuan notes
Java Yes 5 A standard note ( As summarized above ), as well as 5 Seed notes (meta-annotation):
The role of meta annotation is to annotate other annotations .Java5.0 Defined 4 A standard meta-annotation type , They are used to provide for other annotation Description of type .Java5.0 Meta annotation of definition :
1. @Target,
2. @Retention,
3. @Documented,
4. @Inherited
5. @Repeatable
@Target:
@Target Illustrates the Annotation The scope of the object being decorated :Annotation Can be used for packages、types( class 、 Interface 、 enumeration 、Annotation type )、 Type members ( Method 、 Construction method 、 Member variables 、 Enumerated values )、 Method parameters and local variables ( Like loop variables 、catch Parameters ).
effect : Used to describe the scope of use of annotations ( namely : Where can the described annotation be used )
Value (ElementType) Yes :
1. CONSTRUCTOR: Used to describe a constructor ;
2. FIELD: For field declaration ( Include enum example );
3. LOCAL_VARIABLE: Used to describe local variables ;
4. METHOD: Used to describe a method ;
5. PACKAGE: Used to describe a package ;
6. PARAMETER: Used to describe parameters ;
7. TYPE: class 、 Interface ( Including annotation types ) or enum Statement .
@Retention:
@Retention Defines how long annotation information is retained : some Annotation Only in source code , It's discarded by the compiler ; Others are compiled in class In file ; Compile in class In the document Annotation May be ignored by virtual machine , And others are class Will be read when loaded ( Please note that it does not affect class Implementation , because Annotation And class It is separated in use ). Use this meta-Annotation It can be done to Annotation Of “ Life cycle ” Limit .
effect : Indicates at what level the annotation information needs to be saved , Used to describe the life cycle of annotations ( namely : To what extent are the comments described valid )
Value (RetentionPoicy) Yes :
1.SOURCE: Valid in source file ( That is, source file retention ), Annotations are discarded by the compiler ;
2.CLASS: stay class Valid in file ( namely class Retain ) But will be VM discarded ;
3.RUNTIME:VM Valid at run time ( That is, keep it at run time ), Therefore, the information of the annotations can be read through the reflection mechanism
@Documented: Save this comment in Javadoc in .
@Inherited: Allow subclasses to inherit annotations from their parents .
@Repeatable: Allow an annotation to be used once or more .
Most of the time , Programmers define their own annotations , And write your own annotation processor .
Use @interface When customizing annotations , Automatically inherited java.lang.annotation.Annotation Interface
- @interface Used to declare an annotation , Format :public @interface Annotation name { Define content }
- Each of these methods actually declares a configuration parameter
- The parameter of a method is the name of the parameter
- The return value type is the type of the parameter ( The return value can only be a base type ,Class,String,enum)
- Can pass default To declare the default value of the parameter
- If there is only one parameter member , The general parameter name is value
2. Write annotation handler
If there is no tool for reading annotations , Then annotations are the same as annotations . A very important part of using annotations is , Create and use annotation processors .Java It expands the reflection mechanism API To help you create such tools . It also provides javac The compiler uses annotations at compile time .
Here is a simple annotation processor .
public class UseCaseTracker {
public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
for (Method m : cl.getDeclaredMethods()) {
//
UseCase uc = m.getAnnotation(UseCase.class);
if (uc != null) {
System.out.println("Found Use Case " + uc.id() + "\n" + uc.description());
useCases.remove(Integer.valueOf(uc.id()));
}
}
useCases.forEach(i -> System.out.println("Missing use case " + i));
}
public static void main(String[] args) {
List<Integer> collect = IntStream.range(47, 51)
.boxed().collect(Collectors.toList());
trackUseCases(collect, PasswordUtils.class);
}
}
/* outputs: Found Use Case 48 no description Found Use Case 47 Password must contain at least one numeric Found Use Case 49 New password can't equal previously used ones Missing use case 50 */
2.1 Default limit
The compiler is a little too picky about the default values of elements . First , An element cannot have an indefinite value , in other words , Elements either have values , Or use the value provided by the annotation .
When defining default values , When an element is missing or does not exist , Some special values can be customized , For example, an empty string or a negative number indicates .
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SimulatingNull {
int id() default -1;
String description() default "";
}
2.2 Generate external files
When some frameworks need some extra information to work with your source code , In this case, annotations can be very useful .
image Enterprise JavaBeans(EJB3 Before ) Technology like this , every last Bean A large number of interfaces and deployment description files are required . Network services 、 Custom label libraries and objects / Relational mapping tools ( Such as Hibernate) It's usually necessary to XML Description file , And these files are out of the code .
Except for the definition Java class , The programmer must also provide some information , For example, the class name and package name have been provided . Whenever you use an external description file , It has two independent information sources of a class , This often leads to code synchronization problems . It also requires programmers to know how to write code while , You must also know how to describe the file .
If you want to provide some basic objects / Relation mapping function , Ability to automatically generate database tables . You can use XML Describe the file to indicate the name of the class , Information about each member and the database map . however , By using annotations , You can save all the information in JavaBean In the source file . So , You need something to define the database table names 、 Database columns and will SQL Type mapping to comment on property .
The following is the definition of an annotation , It tells the annotation processor that it should create a database table :
@Target(ElementType.TYPE) // This custom annotation can only be used for the specified type , You can specify enum ElementType One of them , Or specify multiple values separated by commas .
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
/** * Use this element to provide the name of the table when the processor creates the database * @return Table name */
String name() default "";
}
The following are the comments that decorate the fields :
/** * This annotation allows the processor to provide metadata for database tables , It represents a small subset of the constraints that databases typically provide , But the idea it wants to express is very clear * @Date 2022/1/12 10:03 * @Created by gt136 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
/*********************************************************/
/** * SQLString Definition is SQL type , If you want this framework to be valuable , We should do it for every SQL Types define the corresponding annotations . Here are two (SQLString、SQLInteger) Just as an example * @Date 2022/1/12 10:08 * @Created by gt136 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
/** * The function of nested annotation is used , The type constraint information of database column is embedded in it * Be careful :constraints() The default value of is {@link @Constraints} * Because in Constraints After annotation type , Not specified in brackets {@link @Constraints} The value of the element , So the value is the default * @return Constraints Default annotation for */
Constraints constraints() default @Constraints;
}
/*********************************************************/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
String name() default "";
Constraints constraints() default @Constraints;
}
these SQL All types have name() and constraints() Elements . The latter uses nested annotations .constraints() The default value of is @Constraints. If you want to change its value , You can define it like this :
public @interface Uniqueness {
// By definition like this constraints() Value
Constraints constraints() default @Constraints(unique = true);
}
The following is a simple class that uses the above annotation :
/** * Create database tables based on annotations * @Date 2022/1/12 10:56 * @Created by gt136 */
@DBTable(name = "Member") // Table, Member
public class Member {
@SQLString(30) // Set the value to 30
String firstName;
@SQLString(50) //
String lastName;
@SQLInteger
Integer age;
// Primary key
@SQLString(value = 30, name = "", constraints = @Constraints(primaryKey = true))
String reference;
static int memberCount;
public String getReference() {
return reference; }
public String getFirstName() {
return firstName; }
public String getLastName() {
return lastName; }
@Override
public String toString() {
return reference; }
public Integer getAge() {
return age; }
}
These notes have Two Interesting places : First , They all use embedded @Constraints Default value for annotation , secondly , They all apply the shortcut feature of annotations . That is, if you define the name in the annotation value The elements of , And when using this annotation ,value Value is the only element you need to assign , You don't need to use name —— value The syntax of assignment , Just give the value directly .
2.3 Implementation processor
Here is an example of an annotation processor :
/** * Reflection based annotation processor * @Date 2022/1/12 15:04 * @Created by gt136 */
public class TableCreator {
public static void main(String[] args) throws ClassNotFoundException {
if (args.length < 1) {
System.out.println("arguments: annotated classes");
System.exit(0);
}
for (String className : args) {
Class<?> aClass = Class.forName(className);
DBTable dbTable = aClass.getAnnotation(DBTable.class);
if (dbTable == null) {
System.out.println("No DBTable annotations in class" + className);
continue;
}
String tableName = dbTable.name();
/** * If no table name is defined , The class name is used as the table name */
if (tableName.length() < 1) {
tableName = aClass.getName().toUpperCase();
}
List<String> columDefs = new ArrayList<>();
// Traversing fields
for (Field declaredField : aClass.getDeclaredFields()) {
String columnName;
// Get the annotation on the field
Annotation[] annos = declaredField.getDeclaredAnnotations();
if (annos.length < 1) {
// There are no columns in the database table , Skip this field directly
continue;
}
// If it is SQLInteger Annotation type
if (annos[0] instanceof SQLInteger) {
SQLInteger sInt = (SQLInteger) annos[0];
//
if (sInt.name().length() < 1) {
columnName = declaredField.getName().toUpperCase();
}else {
columnName = sInt.name();
}
columDefs.add(columnName + " INT" + getConstraints(sInt.constraints()));
}
// If it is SQLString Annotation type
if (annos[0] instanceof SQLString) {
SQLString sString = (SQLString) annos[0];
//
if (sString.name().length() < 1) {
columnName = declaredField.getName().toUpperCase();
}else {
columnName = sString.name();
}
columDefs.add(columnName + " VARCHAR(" + sString.value() + ")" +
getConstraints(sString.constraints()));
}
// The following two paragraphs remove the loop and directly generate the final result
StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");
for (String columDef : columDefs) {
createCommand.append("\n " + columDef + ",");
}
// Remove extra empty
String tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");";
System.out.println("Table Creation SQL for " + className + " is:\n" + tableCreate);
}
}
}
private static String getConstraints(Constraints constraints) {
String cons = "";
if (!constraints.allowNull()) {
cons += " NOT NULL";
}
if (constraints.primaryKey()) {
cons += " PRIMARY KEY";
}
if (constraints.unique()) {
cons += " UNIQUE";
}
return cons;
}
}
/* outputs: Table Creation SQL for com.gui.demo.thingInJava.annotation.database.Member is: CREATE TABLE Member( FIRSTNAME VARCHAR(30)); Table Creation SQL for com.gui.demo.thingInJava.annotation.database.Member is: CREATE TABLE Member( FIRSTNAME VARCHAR(30), LASTNAME VARCHAR(50)); Table Creation SQL for com.gui.demo.thingInJava.annotation.database.Member is: CREATE TABLE Member( FIRSTNAME VARCHAR(30), LASTNAME VARCHAR(50), AGE INT); Table Creation SQL for com.gui.demo.thingInJava.annotation.database.Member is: CREATE TABLE Member( FIRSTNAME VARCHAR(30), LASTNAME VARCHAR(50), AGE INT, REFERENCE VARCHAR(30) NOT NULL PRIMARY KEY); */
Nested @Constraint Annotations are passed to getConstraints() Method , And use it to construct a containing SQL Constrained String object .
The above demonstration techniques are useful for real objects / mapping In relation to , Not quite in line with .
3. Use javac Handle comments
adopt javac , You can do this by creating compile time (compile-time)_ Annotation processor _ stay java Use annotations on source files , Not compiled class file .
But you can't change the source code through the processor , The only way to affect the output is to create a new file . If your annotation processor creates a new source file , In the new round of processing, the annotation will check the source file itself . The tool continues to cycle after one test round , Until no new source files are generated , Then it compiles all the source files .
Every annotation you write requires a processor , however javac It is very easy to merge multiple annotation processors together . You can specify multiple classes to handle , And you can add a listener to listen for the notification after the annotation processing is completed .
3.1 Simplest processor
@Retention(
RetentionPolicy.SOURCE //retention The argument to is now SOURCE, This means that annotations do not persist in compiled code
)
@Target({
ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR,
ElementType.ANNOTATION_TYPE, ElementType.PACKAGE,
ElementType.FIELD, ElementType.LOCAL_VARIABLE})
public @interface Simple {
String value() default "-default-";
}
/*====================================*/
@Simple
public class SimpleTest {
@Simple
int i;
@Simple
public SimpleTest() {
}
@Simple
public void foo() {
System.out.println("SimpleTest.fool()");
}
@Simple
public void bar(String s, int i, float f) {
System.out.println("SimpleTest.bar()");
}
@Simple
public static void main(String[] args) {
@Simple
SimpleTest st = new SimpleTest();
st.foo();
}
}
@Simple
public class SimpleTest {
@Simple
int i;
@Simple
public SimpleTest() {
}
@Simple
public void foo() {
System.out.println("SimpleTest.fool()");
}
@Simple
public void bar(String s, int i, float f) {
System.out.println("SimpleTest.bar()");
}
@Simple
public static void main(String[] args) {
@Simple
SimpleTest st = new SimpleTest();
st.foo();
}
}
@SupportedAnnotationTypes("com.gui.demo.thingInJava.annotation.simplelist.Simple") // Determine which annotations are supported
@SupportedSourceVersion(SourceVersion.RELEASE_8) // Supported by Java edition
public class SimpleProcessor extends AbstractProcessor {
/** * The only thing that needs to be realized is process(), This is where all the behavior takes place . The first parameter tells us which annotation exists , The second parameter holds the remaining information . * <p>for Cycle through the notes </p> * @param annotations Which annotation exists * @param roundEnv Remaining information * @return */
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// Print notes
for (TypeElement t : annotations) {
System.out.println(t);
}
// Cycle through all the @Simple Elements of annotation , And call... For each element display()
for (Element element : roundEnv.getElementsAnnotatedWith(Simple.class)) {
display(element);
}
return false;
}
/** * Each element shows its basic information * @param element By Simple Elements of annotation */
private void display(Element element) {
System.out.println("==== " + element + " ===");
System.out.println(element.getKind() + " : " +
element.getModifiers() + " : " +
element.getSimpleName() + "" +
element.asType());
if (element.getKind().equals(ElementKind.CLASS)) {
TypeElement el = (TypeElement) element;
System.out.println(el.getQualifiedName());
System.out.println(el.getSuperclass());
System.out.println(el.getEnclosedElements());
}
if (element.getKind().equals(ElementKind.METHOD)) {
ExecutableElement ex = (ExecutableElement) element;
System.out.print(ex.getReturnType() + " ");
System.out.print(ex.getSimpleName() + "(");
System.out.println(ex.getParameters()+")");
}
}
}
/* outputs: annotations.simplest.Simple ==== annotations.simplest.SimpleTest ==== CLASS : [public] : SimpleTest : annotations.simplest.SimpleTest annotations.simplest.SimpleTest java.lang.Object i,SimpleTest(),foo(),bar(java.lang.String,int,float),main(java.lang.String[]) ==== i ==== FIELD : [] : i : int ==== SimpleTest() ==== CONSTRUCTOR : [public] : <init> : ()void ==== foo() ==== METHOD : [public] : foo : ()void void foo() ==== bar(java.lang.String,int,float) ==== METHOD : [public] : bar : (java.lang.String,int,float)void void bar(s,i,f) ==== main(java.lang.String[]) ==== METHOD : [public, static] : main : (java.lang.String[])void void main(args) */
Element Only all of those parsed by the compiler can be executed The basic objects share The operation of , and Classes and methods Something like that has extra information to extract . So you check that it's the kind of ElementKind, Then down to more specific element types , Injection is aimed at CLASS Of TypeElement And for METHOD Of ExecutableElement. here , You can call other methods for these elements .
Dynamic downward transformation ( The compiler is not checked ) It's not like Java Your style of doing things .
3.2 More complex processors
When you create for javac Annotation processor for , You can't use Java The reflective properties of , Because you are dealing with the source code , Not compiled class file .
边栏推荐
- [practice] stm32mp157 development tutorial FreeRTOS system 6: FreeRTOS list and list items
- 为什么 C# 访问 null 字段会抛异常?
- 【实战】STM32 FreeRTOS移植系列教程1:FreeRTOS 二值信号量使用
- Quick sort_ sort
- R language uses as The date function converts a single character variable to date data and specifies the format of the data format conversion
- Vuforia引擎支持的版本
- Unity中的地平面简介
- NLog自定义Target之MQTT
- ADO. Net - invalid size for size property, 0 - ado NET - The Size property has an invalid size of 0
- 如何做一个有趣的人
猜你喜欢

智能制造的下一站:云原生+边缘计算双轮驱动

The skill of using ADB and the principle of USB communication

The next stop of Intelligent Manufacturing: cloud native + edge computing two wheel drive

Lodash real on demand approach

leetcode:19. Delete the penultimate node of the linked list

Alibaba cloud OSS uploading and intelligent image recognition garbage recognition

Introduction and template of segment tree Foundation (I)

Zhihu wanzan: what kind of programmers are still wanted by the company after the age of 35? Breaking the "middle age crisis" of programmers

stm32mp1 Cortex M4开发篇9:扩展板空气温湿度传感器控制

How to connect the Internet - FTTH
随机推荐
The skill of using ADB and the principle of USB communication
Alibaba cloud OSS uploading and intelligent image recognition garbage recognition
Full stack development
Common shortcut keys for idea
109. use of usereducer in hooks (counter case)
音视频同步你一定要注意的知识点:
[practice] stm32mp157 development tutorial FreeRTOS system 6: FreeRTOS list and list items
Electron checks the CPU and memory performance when the module is introduced
注解的定义以及注解编译器
QRcode dependency
Observation on the salary data of the post-90s: poor, counselled and serious
It is said that this year gold three silver four has become gold one silver two.
TC software detailed design document (mobile group control)
Judge the data type of JS
Request and response must know
stm32mp1 Cortex M4开发篇13:扩展板按键外部中断
Zhihu wanzan: what kind of programmers are still wanted by the company after the age of 35? Breaking the "middle age crisis" of programmers
Introduction to ground plane in unity
[vs], [usage problem], [solution] when VS2010 is opened, it stays in the startup interface
字符串