Sam*_*ell 9 java annotations annotation-processing java-compiler-api
假设一个类定义了一个常量字段:
public class Foo {
public static final int CONSTANT_FIELD = 3;
}
Run Code Online (Sandbox Code Playgroud)
并假设注释接口声明如下:
public @interface Something {
int value();
}
Run Code Online (Sandbox Code Playgroud)
最后,假设注释使用如下:
@Something(Foo.CONSTANT_FIELD)
Run Code Online (Sandbox Code Playgroud)
问题:在注释处理器中,如何CONSTANT_FIELD从设置值中获取元素@Something?
编辑:在问题本身中包含一个具体的例子.
我有一个像这样使用的注释:
@RuleDependency(recognizer = BQLParser.class,
rule = BQLParser.RULE_statement,
version = 0)
Run Code Online (Sandbox Code Playgroud)
注释处理器需要知道这RULE_statement是在BQLParser类中定义的常量.如果我可以直接从设置注释的属性访问Elementfor ,它将消除对属性的需要.这个注解用来数千次实际应用中,并且是永远只是的声明类型不变.解决这个问题会简化注释用法:BQLParser.RULE_statementrulerecognizerrecognizerrule
@RuleDependency(rule = BQLParser.RULE_statement, version = 0)
Run Code Online (Sandbox Code Playgroud)
我能够使用编译器树 API 来实现此功能。
更新pom.xml以包含以下配置文件,以确保在默认情况下未引用的系统上引用tools.jar 。
<profiles>
<profile>
<!-- Java 6 and earlier have java.vendor set to "Sun Microsystems Inc." -->
<id>default-tools-6.jar</id>
<activation>
<property>
<name>java.vendor</name>
<value>Sun Microsystems Inc.</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</profile>
<profile>
<!-- Java 7 and later have java.vendor set to "Oracle Corporation" -->
<id>default-tools.jar</id>
<activation>
<property>
<name>java.vendor</name>
<value>Oracle Corporation</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</profile>
</profiles>
Run Code Online (Sandbox Code Playgroud)覆盖Processor.init以获取 的实例Trees。
@Override
public void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.trees = Trees.instance(processingEnv);
}
Run Code Online (Sandbox Code Playgroud)实现 a TreePathScanner<TypeMirror, Void>,它用于获取分配给注释中属性TypeMirror的声明类型。rule
private class AnnotationVisitor extends TreePathScanner<TypeMirror, Void> {
@Override
public TypeMirror visitAnnotation(AnnotationTree node, Void p) {
for (ExpressionTree expressionTree : node.getArguments()) {
if (!(expressionTree instanceof AssignmentTree)) {
continue;
}
AssignmentTree assignmentTree = (AssignmentTree)expressionTree;
ExpressionTree variable = assignmentTree.getVariable();
if (!(variable instanceof IdentifierTree) || !((IdentifierTree)variable).getName().contentEquals("rule")) {
continue;
}
return scan(expressionTree, p);
}
return null;
}
@Override
public TypeMirror visitAssignment(AssignmentTree at, Void p) {
return scan(at.getExpression(), p);
}
@Override
public TypeMirror visitMemberSelect(MemberSelectTree mst, Void p) {
return scan(mst.getExpression(), p);
}
@Override
public TypeMirror visitIdentifier(IdentifierTree it, Void p) {
return trees.getTypeMirror(this.getCurrentPath());
}
}
Run Code Online (Sandbox Code Playgroud)为属性提供默认值recognizer。我希望这可以,null但 Java 明确禁止......
/**
* Gets the recognizer class where the dependent parser rules are defined.
* This may reference the generated parser class directly, or for simplicity
* in certain cases, any class derived from it.
* <p>
* If this value is not specified, the default value {@link Parser}
* indicates that the declaring type of the constant value specified for
* {@link #rule} should be used as the recognizer type.
* </p>
*/
Class<? extends Recognizer<?, ?>> recognizer() default Parser.class;
Run Code Online (Sandbox Code Playgroud)更新收集有关应用于代码中RuleDependency特定实例的注释的信息的代码,以首先尝试访问该属性,如果未指定,则改用属性中常量的声明类型。为了简洁起见,此代码示例中省略了错误处理。Elementrecognizerrule
RuleDependency dependency = element.getAnnotation(RuleDependency.class);
// first try to get the parser type from the annotation
TypeMirror recognizerType = getRecognizerType(dependency);
if (recognizerType != null && !recognizerType.toString().equals(Parser.class.getName())) {
result.add(new Triple<RuleDependency, TypeMirror, Element>(dependency, recognizerType, element));
continue;
}
// fallback to compiler tree API
AnnotationMirror annotationMirror = null;
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
if (processingEnv.getTypeUtils().isSameType(ruleDependencyTypeElement.asType(), mirror.getAnnotationType())) {
annotationMirror = mirror;
break;
}
}
AnnotationValue annotationValue = null;
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : annotationMirror.getElementValues().entrySet()) {
if (entry.getKey().getSimpleName().contentEquals("rule")) {
annotationValue = entry.getValue();
break;
}
}
TreePath treePath = trees.getPath(element, annotationMirror, annotationValue);
AnnotationVisitor visitor = new AnnotationVisitor();
recognizerType = visitor.scan(treePath, null);
result.add(new Triple<RuleDependency, TypeMirror, Element>(dependency, recognizerType, element));
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
1010 次 |
| 最近记录: |