java Annotation
Java注解的使用大大地减少了重复性高的代码,且可以流程化一系列的操作。
注解作用域:
- ANNOTATION_TYPE
Annotation type declaration - CONSTRUCTOR
Constructor declaration - FIELD
Field declaration (includes enum constants) - LOCAL_VARIABLE
Local variable declaration - METHOD
Method declaration - PACKAGE
Package declaration - PARAMETER
Formal parameter declaration - TYPE
Class, interface (including annotation type), or enum declaration - TYPE_PARAMETER
Type parameter declaration - TYPE_USE
Use of a type
参考java.lang.annotation.ElementType
。
注解保留策略:
- CLASS
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. - RUNTIME
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. - SOURCE
Annotations are to be discarded by the compiler.
参考java.lang.annotation.RetentionPolicy
。
AbstractProcessor
-
Element
Represents a program element such as a package, class, or method. -
QualifiedNameable
A mixin interface for an element that has a qualified name. -
Parameterizable
A mixin interface for an element that has type parameters. -
PackageElement
Represents a package program element. -
TypeElement
Represents a class or interface program element. -
TypeParameterElement
Represents a formal type parameter of a generic class, interface, method, or constructor element. A type parameter declares aTypeVariable
. -
VariableElement
Represents a field, enum constant, method or constructor parameter, local variable, resource variable, or exception parameter. -
ExecutableElement
Represents a method, constructor, or initializer (static or instance) of a class or interface, including annotation type elements.
源码阶段的Annotation使用
使用方式:
- 定义注解
1 | @Retention(SOURCE) |
- 编译处理类
1 | javac <extends AbstractProcessor .java file>. |
javac -processor <extends AbstractProcessor .java file> <annotation *.java files>.
1 |
|
package com.test;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(SOURCE)
@Target(FIELD)
public @interface Getter {
boolean include() default true;
}
1 |
package com.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Parameterizable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.tools.JavaFileObject;
@SupportedAnnotationTypes(“com.test.Getter”)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class GetterAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (annotations.size() == 0) {
return true;
}
String newSourceFilePackage = "com.test";
String newSourceClassName = "AutoGenCode";
try {
JavaFileObject sourceFile = processingEnv.getFiler()
.createSourceFile(newSourceFilePackage + "." + newSourceClassName);
PrintWriter writer = new PrintWriter(sourceFile.openWriter());
// print code for package and class
StringBuilder sb = new StringBuilder();
sb.append("package ").append(newSourceFilePackage).append(";\n\n");
sb.append("public class ").append(newSourceClassName).append(" {\n\n");
sb.append(blank(4)).append("public ").append(newSourceClassName).append("() {}\n\n");
int i = 0;
for (Element e : roundEnv.getElementsAnnotatedWith(Getter.class)) {
System.out.println("times:" + (i++));
System.out.println("e:" + e);
System.out.println("e instanceof TypeElement:" + (e instanceof TypeElement));
System.out.println("e instanceof VariableElement:" + (e instanceof VariableElement));
System.out.println("e instanceof Parameterizable:" + (e instanceof Parameterizable));
System.out.println("e instanceof TypeParameterElement:" + (e instanceof TypeParameterElement));
if (e instanceof VariableElement) {
VariableElement ve = (VariableElement) e;
writeTo(sb, ve);
}
}
sb.append("\n}");
System.out.println("sb:" + sb);
writer.print(sb);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private void writeTo(StringBuilder sb, VariableElement e) {
System.out.println("IN writeTo....");
String fieldName = e.getSimpleName().toString();
System.out.println("VariableElement.getSimpleName:" + fieldName);
Getter ann = e.getAnnotation(Getter.class);
if (ann != null && ann.include()) {
sb.append(blank(4)).append("public String get");
sb.append(fieldName);
sb.append("() {\n");
sb.append(blank(8)).append("return \"").append(fieldName).append("\";\n");
sb.append(blank(4)).append("}\n\n");
}
System.out.println("OUT writeTo....");
}
private StringBuilder blank(int num) {
StringBuilder sb = new StringBuilder();
while(num--!=0) {
sb.append(" ");
}
return sb;
}
public static void main(String[] args) {
System.out.println(new GetterAnnotationProcessor().blank(4));
}
}
1 |
package com.test.example;
import com.test.Getter; //此处用eclipse会报错,不用理会
public class Test {
@Getter(include = true)
private String abc;
@Getter(include = false)
private String def;
@Getter(include = true)
private String ghi;
public static void main(String[] args) {
}
}
1 |
cd root path:
javac com/test/GetterAnnotationProcessor.java
javac -processor com.test.GetterAnnotationProcessor com/test/example/*.java
编译完成后,在"com/test/"目录下会发现 GetterAnnotationProcessor处理生成的类com.test.AutoGenCode。
1 |
|
package com.test.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- @author w
/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FieldProperty {
/*
* 字段名
*
* @return
*/
String name() default “”;
/**
* 字段编号
*
* @return
*/
int order() default -1;
}
1 |
package com.test;
import com.test.annotation.FieldProperty;
public class UseAnnotation {
@FieldProperty(name = "v1", order = 0)
private String var1;
private String var2;
public String getVar1() {
return var1;
}
public void setVar1(String var1) {
this.var1 = var1;
}
public String getVar2() {
return var2;
}
public void setVar2(String var2) {
this.var2 = var2;
}
}
1 |
package com.test;
import java.lang.reflect.Field;
import com.test.annotation.FieldProperty;
public class Test {
public static void test(Class<?> entity) throws Exception {
Field[] fields = entity.getDeclaredFields();
if (fields == null || fields.length <= 0) {
return;
}
for (Field field : fields) {
FieldProperty fieldProperties = field.getAnnotation(FieldProperty.class);
if (fieldProperties == null) {
throw new Exception(entity.getSimpleName() + " " + field.getName() + " annotation 异常.");
}
if (fieldProperties.order() == -1) {
throw new Exception(entity.getSimpleName() + " " + field.getName() + " 字段未编号.");
}
System.out.println("name:" + fieldProperties.name() + ", order:" + fieldProperties.order());
}
}
public static void main(String[] args) {
try {
test(UseAnnotation.class);
} catch (Exception e) {
e.printStackTrace();
}
}
}
1 |
|
java.lang.Exception: UseAnnotation var2 annotation 异常.
name:v1, order:0
at com.test.Test.test(Test.java:18)
at com.test.Test.main(Test.java:32)
------------
## 参考
- [1] [Maven annotation](https://deors.wordpress.com/2011/10/08/annotation-processors/)