【问题标题】:Use annotation processor generated constants indrectly in annotation will lead compile error在注解中直接使用注解处理器生成的常量会导致编译错误
【发布时间】:2018-07-16 08:54:35
【问题描述】:

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”是因为它在 Eclipse 中使用 ECJ 和 m2e-apt 可以正常工作。

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

【问题讨论】:

  • 尝试通过class ref访问静态var:@Bean(ClassName.HELLO)
  • 我想根据java版本和处理器类的位置,你应该指定一些javac参数来指示编译器这些在哪里。对于 Java 8:docs.oracle.com/javase/8/docs/technotes/tools/windows/…。 IDE 为您做了很多事情。毫不奇怪它可以直接使用它。
  • @Eugen 还是不行
  • @davidxxx 你知道shuold应该加哪个参数吗?
  • 您使用的是什么版本的 java 和 spring?你能发布声明public String bean(){public static final String HELLO的类吗

标签: java annotations javac annotation-processing


【解决方案1】:

我不知道这个主题,所以试着玩了一下。 您的示例似乎不适用于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. with @Anno(HelloWorldMessage.HELLO_WORLD): HelloWorldMessage 无法解析为变量
  2. @Anno(UseHelloWorld.HW):注解属性Anno.value的值必须是常量表达式

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

【讨论】:

  • 感谢您的回答。我在创建最小化测试用例时犯了一些错误。我已经更新了我的案例。你能再试一次吗,我保证它现在会工作但会失败?
  • 当我发现它已经过去了 5 分钟时,我错误地投了反对票。您能否编辑您的答案,以便我可以恢复我的否决票。
  • @DeanXu 我已经更新了我的答案,你的例子很有趣,我实际上认为这是编译器的限制。
  • 对于这样的常量,编译器会内联它。所以直接和间接的用法应该没有区别。我已经向 oracle 报告了这个错误。
  • @DeanXu 我不确定这里是否会发生内联,因为要生成HelloWorldMessage。我认为在这个阶段,编译器只检索有关注解类型的信息进行处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-26
  • 2012-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多