使用注释方法时使java编译器发出警告(如@deprecated) [英] Make the java compiler warn when an annotated method is used (like @deprecated)

查看:2014
本文介绍了使用注释方法时使java编译器发出警告(如@deprecated)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我定义了一个名为 @Unsafe 的自定义注释。



我想提供注释处理器将检测引用到以 @Unsafe 注释的方法并打印警告。



例如,给定此代码...

  Foo {
@Unsafe
public void doSomething(){...}
}

public class Bar {
public static void main(String [ ] args){
new Foo()。doSomething();
}
}

...我想让编译器打印:

  WARN> Bar.java,第3行:调用Unsafe API  -  Foo.doSomething()

在精神上 @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(){
returnUnsafePlugin;
}

@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){
元素方法= 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){
}

}
注意 - 为了调用javac插件,您必须在命令行中提供参数:



  javac -processorpath build / unsafe-plugin.jar -Xplugin:UnsafePlugin 

此外,您必须在不安全文件中有一个文件 META-INF / services / com.sun.source.util.Plugin -plugin.jar包含插件的完全限定名:

  com.unsafetest.javac.UnsafePlugin 


Let's say I define a custom annotation called @Unsafe.

I'd like to provide an annotation processor which will detect references to methods annotated with @Unsafe and print a warning.

For example, given this code ...

public class Foo {
  @Unsafe
  public void doSomething() { ... }
}

public class Bar {
  public static void main(String[] args) {
    new Foo().doSomething();
  }
}

... I want the compiler to print something like:

WARN > Bar.java, line 3 : Call to Unsafe API - Foo.doSomething()

It is very similar in spirit to @Deprecated, but my annotation is communicating something different, so I can't use @Deprecated directly. Is there a way to achieve this with an annotation processor? The annotation processor API seems to be more focused on the entities applying the annotations (Foo.java in my example) than entities which reference annotated members.

This question provides a technique to achieve it as a separate build step using ASM. But I'm wondering if I can do it in a more natural way with javac & annotation processing?

解决方案

I think I could have technically achieved my goal using the response from @mernst, so I appreciate the suggestion. However, I found another route that worked better for me as I'm working on a commercial product and cannot incoporate the Checker Framework (its GPL license is incompatible with ours).

In my solution, I use my own "standard" java annotation processor to build a listing of all the methods annotated with @Unsafe.

Then, I developed a javac plugin. The Plugin API makes it easy to find every invocation of any method in the AST. By using some tips from this question, I was able to determine the class and method name from the MethodInvocationTree AST node. Then I compare those method invocations with the earlier "listing" I created containing methods annotated with @Unsafe and issue warnings where required.

Here is an abbreviated version of my javac Plugin.

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) {
  }

}

Note - in order for the javac plugin to be invoked, you must provide arguments on the command line:

javac -processorpath build/unsafe-plugin.jar -Xplugin:UnsafePlugin

Also, you must have a file META-INF/services/com.sun.source.util.Plugin in unsafe-plugin.jar containing the fully qualified name of the plugin:

com.unsafetest.javac.UnsafePlugin

这篇关于使用注释方法时使java编译器发出警告(如@deprecated)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆