我可以将类的名称作为编译时常量获得,而无需在字符串文字中对其进行硬编码吗?

时间:2015-01-15 00:53:15

标签: java reflection constants compile-time-constant

我正在研究注释处理器。此代码编译:

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())

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

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

2 个答案:

答案 0 :(得分:6)

您的处理器可以实现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<?>[]而不是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());
}

答案 1 :(得分:5)

您可以定义自己的。

public @interface SupportedAnnotationTypes_Class {
    Class supported();
}

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