我可以在不将 class 的名称硬编码为字符串文字的情况下将其作为编译时常量吗?
Can I get a class's name as a compile-time constant without hardcoding it in a string literal?
我正在研究注释处理器。此代码编译:
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 文字强制转换为它的名称吗?
您的处理器可以实现 getSupportedAnnotationTypes()
以在运行时提供支持的注释类型名称,而不是使用注释:
Set<String> getSupportedAnnotationTypes() {
Set<String> supportedAnnotationTypes = new HashSet<>();
supportedAnnotationTypes.add(Foo.class.getName());
return supportedAnnotationTypes;
}
如果您想为此继续使用(非标准)注解,您可以创建自己的注解,将编译时类型作为参数,如@k_g 所建议的那样。 @SupportedAnnotationTypes isn't really anything special, it is only used automatically when you are extending AbstractProcessor
anyway. Take a look at the 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());
}
您可以定义自己的。
public @interface SupportedAnnotationTypes_Class {
Class supported();
}
然后用@SupportedAnnotationTypes_Class(supported = sand.Foo.class)
来使用。
我正在研究注释处理器。此代码编译:
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 文字强制转换为它的名称吗?
您的处理器可以实现 getSupportedAnnotationTypes()
以在运行时提供支持的注释类型名称,而不是使用注释:
Set<String> getSupportedAnnotationTypes() {
Set<String> supportedAnnotationTypes = new HashSet<>();
supportedAnnotationTypes.add(Foo.class.getName());
return supportedAnnotationTypes;
}
如果您想为此继续使用(非标准)注解,您可以创建自己的注解,将编译时类型作为参数,如@k_g 所建议的那样。 @SupportedAnnotationTypes isn't really anything special, it is only used automatically when you are extending AbstractProcessor
anyway. Take a look at the 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());
}
您可以定义自己的。
public @interface SupportedAnnotationTypes_Class {
Class supported();
}
然后用@SupportedAnnotationTypes_Class(supported = sand.Foo.class)
来使用。