一个选项是annotation processor。例如,如果您有以下注释:
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME) // must be at least SOURCE
@Target(ElementType.FIELD)
public @interface Foo {}
如果@Foo 出现在final 字段上,则以下内容将发出错误:
package com.example;
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.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import java.util.Set;
@SupportedAnnotationTypes("com.example.Foo")
@SupportedSourceVersion(SourceVersion.RELEASE_13) // or whatever version you support
public class FooProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!annotations.isEmpty()) {
// This processor is only declared to process one annotation
TypeElement foo = annotations.iterator().next();
for (Element element : roundEnv.getElementsAnnotatedWith(foo)) {
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
if (mirror.getAnnotationType().asElement().equals(foo)
&& element.getModifiers().contains(Modifier.FINAL)) {
// processingEnv is a protected field of AbstractProcessor
processingEnv.getMessager()
.printMessage(Kind.ERROR, "Field cannot be final.", element, mirror);
break;
}
}
}
}
return true;
}
}
在上面的代码中,我只使用了模型 API(例如 TypeElement)来引用 Foo 注释。但是请注意,如果注释可见(即您的处理器依赖于注释),注释处理器 API 确实允许使用注释的类(例如 Foo.class)。使用类 API 可以更易于使用、更易于推理和更易于阅读 - 如果您的注解类对您的处理器类可见,则使用它。
然后您需要告诉javac 使用注释处理器。请参阅tool specification 了解更多信息;具体来说,请查看--processor-path、--processor-module-path、-processor 和-proc 标准选项以及the section 注释处理。
请注意,您可能无法强制使用注释处理器。