首页 > 解决方案 > 在注解中直接使用注解处理器生成的常量会导致编译错误

问题描述

获取最小化代码来重现这个

我有一个HelloWorldProcessor谁会简单地生成源文件HelloWorldMessage.java

public interface HelloWorldMessage { 
  String HELLO_WORLD = "Hello World";
}

现在我在我的代码中使用生成的值:

public class UseHelloWorld {
  @Anno(HelloWorldMessage.HELLO_WORLD)
  public void func(){
  }
}

这很好用。

但是如果我将值声明为常量并间接使用它,则会导致编译错误。

public class UseHelloWorld{
  public static final String HW =  HelloWorldMessage.HELLO_WORLD;

  @Anno(UseHelloWorld.HW)
  public void func(){
  }
}

Javac 给出symbol not found错误:

UseHelloWorld.java:2: error: cannot find symbol
  public static final String HW = HelloWorldMessage.HELLO_WORLD;
                                  ^
  symbol:   variable HelloWorldMessage
  location: class UseHelloWorld
UseHelloWorld.java:4: error: element value must be a constant expression
  @Anno(UseHelloWorld.HW)
                     ^
2 errors

为什么我说'javac'是因为它在带有ECJ和m2e-apt的eclipse中运行良好。

这是一个javac错误吗?如果不是,我如何才能正确地间接使用生成的源?

标签: javaannotationsjavacannotation-processing

解决方案


我不知道这个主题,所以试着玩了一下。看来您的示例不适用于javac,按照您提供的步骤,我认为不会调用处理器。您可以尝试使用一些调试参数来验证它:

  1. -XprintProcessorInfo:打印有关要求处理器处理哪些注释的信息
  2. -XprintRounds:打印有关初始和后续注释处理轮次的信息。
  3. -verbose:详细输出。这包括有关加载的每个类和编译的每个源文件的信息。

其次,您似乎需要将处理器作为罐子提供,其中包含/META-INF/services/javax.annotation.processing.Processor。我试过这个,它更好但仍然失败,我认为这是因为源文件没有编译,所以编译器无法检索有关注释的任何信息。(我认为只需扫描源文件就可以)。

最后,我通过将注释的使用从UseHelloWorld一个package-info.java文件(或任何其他可编译的文件)移到它的工作。现在编译器可以看到注释已在源文件中使用,并且处理器被调用以生成HelloWorldMessage在下一轮编译的类。并且该类UseHelloWorld也可以编译。

注意:我在您的文件中添加了一些importpackage,否则即使存在HelloWorldMessage类也无法编译。

我认为它在 Eclipse 中工作的原因是因为正在使用不同的工具来进行处理。或者,也许您已经生成了一段时间的源文件而忘记清理它。希望有人能给出更好的答案,我只是分享我的实验。


更新

我说我们应该将处理器作为 jar 提供,这很愚蠢,显然一个类文件就足够了(我可能使用了错误的类路径)。我对更新后的帖子的猜测是编译器不能处理所有情况。在 Eclipse 中,我们看到两个不同的错误@Anno

  1. with @Anno(HelloWorldMessage.HELLO_WORLD): HelloWorldMessage 无法解析为变量
  2. with @Anno(UseHelloWorld.HW):注解属性 Anno.value 的值必须是常量表达式

也许在第一种情况下,编译器足够聪明地猜测注释处理器可以生成未知类型,所以它会尝试,而在第二种情况下,它会将其视为注释使用不正确。


推荐阅读