gre*_*ill 12 java compiler-construction annotations deprecated
假设我定义了一个名为的自定义注释@Unsafe
.
我想提供一个注释处理器,它将检测对注释方法的引用@Unsafe
并打印警告.
例如,鉴于此代码......
public class Foo {
@Unsafe
public void doSomething() { ... }
}
public class Bar {
public static void main(String[] args) {
new Foo().doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
...我希望编译器打印如下:
WARN > Bar.java, line 3 : Call to Unsafe API - Foo.doSomething()
Run Code Online (Sandbox Code Playgroud)
它在精神上非常相似@Deprecated
,但我的注释是在传达不同的东西,所以我不能@Deprecated
直接使用.有没有办法用注释处理器实现这一目标?注释处理器API似乎更关注应用注释的实体(Foo.java
在我的示例中),而不是引用注释成员的实体.
此问题提供了一种使用ASM作为单独构建步骤实现它的技术.但我想知道我是否可以通过javac和注释处理以更自然的方式做到这一点?
我想我可以使用@mernst 的回复在技术上实现我的目标,所以我很感激这个建议。但是,我发现了另一条更适合我的路线,因为我正在开发商业产品并且无法合并 Checker 框架(它的 GPL 许可证与我们的不兼容)。
在我的解决方案中,我使用我自己的“标准”Java 注释处理器来构建所有用@Unsafe
.
然后,我开发了一个 javac 插件。插件 API 可以轻松找到 AST 中任何方法的每次调用。通过使用此问题中的一些提示,我能够从 MethodInvocationTree AST 节点确定类和方法名称。然后,我将这些方法调用与我创建的包含注释的方法的早期“列表”进行比较,@Unsafe
并在需要时发出警告。
这是我的 javac 插件的缩写版本。
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskEvent.Kind;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.source.util.TaskListener;
import com.sun.source.util.TreeScanner;
public class UnsafePlugin implements Plugin, TaskListener {
@Override
public String getName() {
return "UnsafePlugin";
}
@Override
public void init(JavacTask task, String... args) {
task.addTaskListener(this);
}
@Override
public void finished(TaskEvent taskEvt) {
if (taskEvt.getKind() == Kind.ANALYZE) {
taskEvt.getCompilationUnit().accept(new TreeScanner<Void, Void>() {
@Override
public Void visitMethodInvocation(MethodInvocationTree methodInv, Void v) {
Element method = TreeInfo.symbol((JCTree) methodInv.getMethodSelect());
TypeElement invokedClass = (TypeElement) method.getEnclosingElement();
String className = invokedClass.toString();
String methodName = methodInv.getMethodSelect().toString().replaceAll(".*\\.", "");
System.out.println("Method Invocation: " + className + " : " + methodName);
return super.visitMethodInvocation(methodInv, v);
}
}, null);
}
}
@Override
public void started(TaskEvent taskEvt) {
}
}
Run Code Online (Sandbox Code Playgroud)
注意 - 为了调用 javac 插件,您必须在命令行上提供参数:
javac -processorpath build/unsafe-plugin.jar -Xplugin:UnsafePlugin
Run Code Online (Sandbox Code Playgroud)
此外,您必须META-INF/services/com.sun.source.util.Plugin
在 unsafe-plugin.jar 中有一个文件,其中包含插件的完全限定名称:
com.unsafetest.javac.UnsafePlugin
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1526 次 |
最近记录: |