使用注释处理器编译时间处理
此示例演示如何对带注释的元素进行编译时检查。
注释
@Setter
注释是可以应用于方法的标记。注释将在编译期间被丢弃,之后无法使用。
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Setter {
}
注释处理器
编译器使用 SetterProcessor
类来处理注释。如果使用 @Setter
注释注释的方法是 public
,则检查名称以 set
开头且大写字母为第 4 个字母的非 static
方法。如果不满足其中一个条件,则会向 Messager
写入错误。编译器将此写入 stderr,但其他工具可能以不同方式使用此信息。例如,NetBeans IDE 允许用户指定用于在编辑器中显示错误消息的注释处理器。
package annotation.processor;
import annotation.Setter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
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.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
@SupportedAnnotationTypes({"annotation.Setter"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SetterProcessor extends AbstractProcessor {
private Messager messager;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// get elements annotated with the @Setter annotation
Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Setter.class);
for (Element element : annotatedElements) {
if (element.getKind() == ElementKind.METHOD) {
// only handle methods as targets
checkMethod((ExecutableElement) element);
}
}
// don't claim annotations to allow other processors to process them
return false;
}
private void checkMethod(ExecutableElement method) {
// check for valid name
String name = method.getSimpleName().toString();
if (!name.startsWith("set")) {
printError(method, "setter name must start with \"set\"");
} else if (name.length() == 3) {
printError(method, "the method name must contain more than just \"set\"");
} else if (Character.isLowerCase(name.charAt(3))) {
if (method.getParameters().size() != 1) {
printError(method, "character following \"set\" must be upper case");
}
}
// check, if setter is public
if (!method.getModifiers().contains(Modifier.PUBLIC)) {
printError(method, "setter must be public");
}
// check, if method is static
if (method.getModifiers().contains(Modifier.STATIC)) {
printError(method, "setter must not be static");
}
}
private void printError(Element element, String message) {
messager.printMessage(Diagnostic.Kind.ERROR, message, element);
}
@Override
public void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
// get messager for printing errors
messager = processingEnvironment.getMessager();
}
}
打包
要由编译器应用,需要使注释处理器可用于 SPI(请参阅 ServiceLoader )。
为此,除了其他文件之外,还需要将文本文件 META-INF/services/javax.annotation.processing.Processor
添加到包含注释处理器和注释的 jar 文件中。该文件需要包含注释处理器的完全限定名称,即它应该如下所示
annotation.processor.SetterProcessor
我们假设 jar 文件在下面被称为 AnnotationProcessor.jar
示例注释类
以下类是默认包中的示例类,其中注释根据保留策略应用于正确的元素。但是,只有注释处理器才将第二种方法视为有效的注释目标。
import annotation.Setter;
public class AnnotationProcessorTest {
@Setter
private void setValue(String value) {}
@Setter
public void setString(String value) {}
@Setter
public static void main(String[] args) {}
}
使用带有 javac 的注释处理器
如果使用 SPI 发现注释处理器,则会自动使用它来处理带注释的元素。例如,使用编译 AnnotationProcessorTest
类
javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java
产生以下输出
AnnotationProcessorTest.java:6: error: setter must be public
private void setValue(String value) {}
^
AnnotationProcessorTest.java:12: error: setter name must start with "set"
public static void main(String[] args) {}
^
2 errors
而不是正常编译。没有创建 .class
文件。
这可以通过为 javac
指定 -proc:none
选项来防止。你也可以通过指定 -proc:only
来放弃通常的编译。
IDE 集成
Netbeans
注释处理器可以在 NetBeans 编辑器中使用。为此,需要在项目设置中指定注释处理器:
-
去
Project Properties
>Build
>Compiling
-
为
Enable Annotation Processing
和Enable Annotation Processing in Editor
添加复选标记 -
单击注释处理器列表旁边的
Add
-
在出现的弹出窗口中输入注释处理器的完全限定类名,然后单击
Ok
。