在注释中不正确地使用注释处理器生成的常量会导致编译错误

时间:2018-07-16 08:54:35

标签: java annotations javac annotation-processing

Get minimize code to reproduce this

我有一个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错误吗?如果没有,我该如何正确地间接使用生成的源?

1 个答案:

答案 0 :(得分:2)

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

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

第二,似乎您需要将处理器提供为jar,其中包含/META-INF/services/javax.annotation.processing.Processor。我已经尝试过了,这更好,但仍然失败了,我认为这是因为源文件未编译,所以编译器无法检索有关注释的任何信息(我认为可以通过扫描源文件来实现)。

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

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

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


更新

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

有关的错误
  1. 使用@Anno(HelloWorldMessage.HELLO_WORLD):HelloWorldMessage无法解析为变量
  2. 带有@Anno(UseHelloWorld.HW):注释属性Anno.value的值必须是一个常量表达式

也许在第一种情况下,编译器足够聪明,可以猜测注释处理器可以生成未知类型,因此可以尝试一下,在第二种情况下,由于注释使用不当,编译器会对其进行处理。