我可以将类的名称作为编译时常量获取而不用字符串文字对其进行硬编码吗?

Sam*_*ard 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
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我对字符串常量"sand.Foo"感到不满(在这种情况下不是太多,但对于将来会更多).

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

我想做的事情如下:

@SupportedAnnotationTypes(Foo.class)
Run Code Online (Sandbox Code Playgroud)

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

但这不起作用,因为a Class不是String.所以我尝试过:

@SupportedAnnotationTypes(Foo.class.getName())
Run Code Online (Sandbox Code Playgroud)

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

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

kap*_*pex 6

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

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



如果你想继续使用(非标准)注释,你可以创建自己的注释,将编译时类型作为参数,如@k_g建议.@SupportedAnnotationTypes并不是什么特别的,它只会在你进行扩展时自动使用AbstractProcessor.看一下源代码AbstractProcessor.getSupportedAnnotationTypes().

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

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

getSupportedAnnotationTypes以与以下相同的方式覆盖和查找自定义注释AbstractProcessor.例如这样:

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


k_g*_*k_g 5

你可以定义自己的.

public @interface SupportedAnnotationTypes_Class {
    Class supported();
}
Run Code Online (Sandbox Code Playgroud)

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