【问题标题】:Can I get a class's name as a compile-time constant without hardcoding it in a string literal?我可以在不将其硬编码为字符串文字的情况下将类的名称作为编译时常量吗?
【发布时间】:2015-03-13 08:36:10
【问题描述】:

我正在开发注释处理器。此代码编译:

package sand;

import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.TypeElement;

@SupportedAnnotationTypes("sand.Foo")
public class FooProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false; // TODO
    }
}

但是,我对字符串常量“sand.Foo”不满意(在这种情况下不是太多,但对于未来来说更普遍)。

如果Foo 被重命名或移动到另一个包,这段代码仍然可以编译,但它不会工作。

我想做这样的事情:

@SupportedAnnotationTypes(Foo.class)

这样,如果 Foo 的名称发生变化,编译将失败,必须有人更正文件。

但这不起作用,因为Class 不是String。所以我尝试了:

@SupportedAnnotationTypes(Foo.class.getName())

但是编译器不认为这是一个常量表达式,在这个上下文中是必需的,所以它也不起作用。

有没有办法在编译时将类文字强制转换为它的名称?

【问题讨论】:

  • 为什么不能使用Class参数而不是String
  • @chrylis SupportedAnnotationTypes 只接受 String... 作为输入。
  • 对不起,我设法错过了这是来自 APT 命名空间的那个。我想您可以定义自己的注释,该注释采用 Class 并使用处理器生成上面的代码?
  • Is there any way to coerce a class literal into its name at compile time? - 不,抱歉,但请参阅 kapep 的答案以获得一个好的选择。

标签: java reflection constants compile-time-constant


【解决方案1】:

您的处理器可以实现 getSupportedAnnotationTypes() 以在运行时提供支持的注解类型名称,而不是使用注解:

Set<String> getSupportedAnnotationTypes() {
    Set<String> supportedAnnotationTypes = new HashSet<>();
    supportedAnnotationTypes.add(Foo.class.getName());
    return supportedAnnotationTypes;
} 



如果您想为此继续使用(非标准)注释,您可以创建自己的注释,将编译时类型作为参数,如@k_g 建议的那样。 @SupportedAnnotationTypes 并没有什么特别之处,它只会在你扩展 AbstractProcessor 时自动使用。看看source code of AbstractProcessor.getSupportedAnnotationTypes()

你的自定义注解的签名应该使用Class&lt;?&gt;[]而不是String[]

@Target(TYPE)
@Retention(RUNTIME)
public @interface SupportedAnnotationTypes {
    Class<?>[] value();
}

覆盖getSupportedAnnotationTypes 并以与AbstractProcessor 相同的方式查找您的自定义注释。比如这样:

public Set<String> getSupportedAnnotationTypes() {
    Class<?>[] types = getClass().getAnnotation(SupportedAnnotationTypes.class).value();
    return Arrays.stream(types).map(Class::getName).collect(Collectors.toSet());
}

【讨论】:

    【解决方案2】:

    您可以定义自己的。

    public @interface SupportedAnnotationTypes_Class {
        Class supported();
    }
    

    然后使用@SupportedAnnotationTypes_Class(supported = sand.Foo.class)来使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-10
      • 2012-08-09
      相关资源
      最近更新 更多