我能否将类的名称作为编译时常量获取,而无需将其硬编码在字符串文本中?

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

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
    }
}

但是,我对弦常数“沙子”感到不满。Foo“(在这种情况下不是太多,但对未来来说更一般)。

如果 重命名或移动到另一个包,此代码仍将编译,但不起作用。Foo

我想做这样的事情:

@SupportedAnnotationTypes(Foo.class)

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

但这不起作用,因为 a 不是 .所以我尝试了:ClassString

@SupportedAnnotationTypes(Foo.class.getName())

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

有没有办法在编译时强制类文字进入其名称?


答案 1

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

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



如果您想继续使用(非标准)注释,则可以创建自己的注释,该注释采用编译时类型作为参数,如@k_g建议的那样。@SupportedAnnotationTypes并不是什么特别的东西,但它只有在你扩展时才会自动使用。看看 AbstractProcessor.getSupportedAnnotationTypes() 的源代码AbstractProcessor

自定义注释的签名应使用而不是 :Class<?>[]String[]

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

以与 相同的方式覆盖和查找自定义注释。例如:getSupportedAnnotationTypesAbstractProcessor

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)


推荐