Java 在注释中直接使用注释处理器生成的常量将导致编译错误

Java 在注释中直接使用注释处理器生成的常量将导致编译错误,java,annotations,javac,annotation-processing,Java,Annotations,Javac,Annotation Processing,我有一个HelloWorldProcessor,他只需生成源文件HelloWorldMessage.java public interface HelloWorldMessage { String HELLO_WORLD = "Hello World"; } 现在,我在代码中使用生成的值: public class UseHelloWorld { @Anno(HelloWorldMessage.HELLO_WORLD) public void func(){ } } 那很好

我有一个
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给出的
符号未找到
错误:

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错误吗?如果没有,我怎样才能正确地间接使用生成的源代码?

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

  • -XprintProcessorInfo
    :打印有关要求处理器处理哪些批注的信息
  • -XprintRounds
    :打印有关初始和后续注释处理循环的信息
  • -verbose
    :详细输出。这包括有关加载的每个类和编译的每个源文件的信息
  • 其次,您似乎需要将处理器作为jar提供,其中包含
    /META-INF/services/javax.annotation.processing.processor
    。我尝试过这个方法,虽然更好,但还是失败了,我认为这是因为源文件没有编译,所以编译器无法检索有关注释的任何信息(我认为可以通过扫描源文件)

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

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

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


    更新

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

  • 使用
    @Anno(HelloWorldMessage.HELLO\u WORLD)
    :无法将HelloWorldMessage解析为变量
  • 使用
    @Anno(UseHelloWorld.HW)
    :注释属性Anno.value的值必须是常量表达式

  • 可能在第一种情况下,编译器足够聪明,可以猜测注释处理器可以生成未知类型,因此它会进行尝试,在第二种情况下,它会将其视为注释使用不当

    尝试通过类ref:@Bean(ClassName.HELLO)访问静态var,我认为根据java版本和处理器类的位置,您应该指定一些javac参数来指示编译器这些参数的位置。对于Java 8:。IDE为您做了很多事情。这并不奇怪,它可以直接与它一起工作。@Eugen,它仍然不是work@davidxxx您知道shuold添加了哪个参数吗?您使用的是什么版本的java和spring?您还可以发布声明为
    公共字符串bean()的类吗{
    公共静态最终字符串您好
    谢谢您的回答。我在创建最小化测试用例时出错。我已经更新了我的用例。您能再试一次吗,我保证它会工作并且现在失败吗?当我发现它已经过去了5分钟时,我错误地投了反对票。您能编辑您的答案以便我可以恢复我的反对票吗。@DeanXu我已经更新了我的答案,您的示例非常有趣,我实际上认为这是编译器的一个限制。对于这样的常量,编译器将内联它。因此直接和间接用法应该没有区别。我已经向oracle报告了该错误。@DeanXu我不确定这里是否会发生内联,因为将生成
    HelloWorldMessage
    。我在这个阶段,编译器只检索有关注释类型的信息进行处理。