gpt4 book ai didi

java - 在注释处理器中获取字段类

转载 作者:IT老高 更新时间:2023-10-28 21:04:10 30 4
gpt4 key购买 nike

我正在编写我的第一个 Annotations 处理器,遇到了一些看似微不足道的问题,但我找不到任何相关信息。

我有一个用我的注释注释的元素

@MyAnnotation String property;

当我在处理器中将此属性作为元素获取时,我似乎无法以任何方式获取元素的类型。在这种情况下,a 会想要获取表示 String 的 Class 或 TypeElement 实例。

我尝试使用 Class.forName() 实例化容器类型的类对象,但它抛出了 ClassNotFoundException。我认为这是因为我无法访问包含该类的类加载器?

最佳答案

运行注释处理器时,您无权访问已编译的类。注释处理的重点是它发生在预编译。

相反,您需要创建一个专门处理您的注释类型的注释处理器,然后使用镜像 API 来访问该字段。例如:

@SupportedAnnotationTypes("com.example.MyAnnotation")
public class CompileTimeAnnotationProcessor extends AbstractProcessor {

@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// Only one annotation, so just use annotations.iterator().next();
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(
annotations.iterator().next());
Set<VariableElement> fields = ElementFilter.fieldsIn(elements);
for (VariableElement field : fields) {
TypeMirror fieldType = field.asType();
String fullTypeClassName = fieldType.toString();
// Validate fullTypeClassName
}
return true;
}
}

对于验证,您不能使用诸如 MyType.class 之类的东西来使用任何尚未编译的类(包括即将使用注释编译的类) >。对于这些,您必须只使用字符串。这是因为注解处理发生在称为“源代码生成”的预编译阶段,这允许您在编译器运行之前使用注解生成源代码。

验证字段类型是否为 java.lang.String(已编译)的示例验证:

for (VariableElement field : fields) {
TypeMirror fieldType = field.asType();
String fullTypeClassName = fieldType.toString();
if (!String.class.getName().equals(fullTypeClassName)) {
processingEnv.getMessager().printMessage(
Kind.ERROR, "Field type must be java.lang.String", field);
}
}

资源

编辑:

I want to get the field type to get annotations on that type. But this does not seem like it will be possible?

确实有可能!这可以在 TypeMirror 上使用更多方法来完成:

if (fieldType.getKind() != TypeKind.DECLARED) {
processingEnv.getMessager().printMessage(
Kind.ERROR, "Field cannot be a generic type.", field);
}
DeclaredType declaredFieldType = (DeclaredType) fieldType;
TypeElement fieldTypeElement = (TypeElement) declaredFieldType.asElement();

从这里开始,您有两个选择:

  1. 如果您要查找的注解已经编译(即它来自另一个库),那么您可以直接引用该类来获取注解。
  2. 如果您要查找的注解没有被编译(即它正在当前调用运行 APT 的 javac 中编译),那么您可以通过 AnnotationMirror 实例。

已经编译

DifferentAnnotation diffAnn = fieldTypeElement.getAnnotation(
DifferentAnnotation.class);
// Process diffAnn

非常简单,这使您可以直接访问注释本身。

未编译

请注意,无论注解是否编译,此解决方案都可以正常工作,只是不如上面的代码干净。

这是我曾经编写的几个方法,用于通过类名从注释镜像中提取某个值:

private static <T> T findAnnotationValue(Element element, String annotationClass,
String valueName, Class<T> expectedType) {
T ret = null;
for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
DeclaredType annotationType = annotationMirror.getAnnotationType();
TypeElement annotationElement = (TypeElement) annotationType
.asElement();
if (annotationElement.getQualifiedName().contentEquals(
annotationClass)) {
ret = extractValue(annotationMirror, valueName, expectedType);
break;
}
}
return ret;
}

private static <T> T extractValue(AnnotationMirror annotationMirror,
String valueName, Class<T> expectedType) {
Map<ExecutableElement, AnnotationValue> elementValues = new HashMap<ExecutableElement, AnnotationValue>(
annotationMirror.getElementValues());
for (Entry<ExecutableElement, AnnotationValue> entry : elementValues
.entrySet()) {
if (entry.getKey().getSimpleName().contentEquals(valueName)) {
Object value = entry.getValue().getValue();
return expectedType.cast(value);
}
}
return null;
}

假设您正在寻找 DifferentAnnotation 注释并且您的源代码如下所示:

@DifferentAnnotation(name = "My Class")
public class MyClass {

@MyAnnotation
private String field;

// ...
}

此代码将打印 My Class:

String diffAnnotationName = findAnnotationValue(fieldTypeElement,
"com.example.DifferentAnnotation", "name", String.class);
System.out.println(diffAnnotationName);

关于java - 在注释处理器中获取字段类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17660469/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com