java—我可以将类名作为编译时常量,而不必硬编码为字符串文本吗?

7gs2gvoe  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(410)

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

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

但是编译器并不认为这是一个常量表达式,这在上下文中是必需的,所以这也不起作用。
有没有什么方法可以在编译时强制将类文字转换成它的名称?

dwbf0jvd

dwbf0jvd1#

处理器可以实现 getSupportedAnnotationTypes() 要在运行时提供支持的注解类型名称,请执行以下操作:

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

如果您想继续为此使用(非标准)注解,您可以创建自己的注解,该注解采用编译时类型作为参数,如@k\g所建议的那样@supportedannotationtypes并不是什么特别的东西,它只在扩展时自动使用 AbstractProcessor 不管怎样。看一下的源代码 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());
}
bgtovc5b

bgtovc5b2#

你可以自己定义。

public @interface SupportedAnnotationTypes_Class {
    Class supported();
}

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

相关问题