[英]Get field class in annotations processor
I am writing my first Annotations processor and having trouble with something that seems trivial but I cannot find any information about it. 我正在编写我的第一个Annotations处理器,并且遇到一些看似微不足道的问题,但我找不到任何有关它的信息。
I have a element annotated with my annotation 我有一个用我的注释注释的元素
@MyAnnotation String property;
When I get this property as a element in my processor I can not seem to get the type of the element in any way. 当我将此属性作为处理器中的元素时,我似乎无法以任何方式获取元素的类型。 In this case a would want to get a Class or TypeElement instance representing String.
在这种情况下,a希望获得表示String的Class或TypeElement实例。
I tried instantiating a class object of the container type with Class.forName()
but it threw a ClassNotFoundException. 我尝试使用
Class.forName()
实例化容器类型的类对象,但它抛出了ClassNotFoundException。 I think this is because I do not have access to the class loader containing the class? 我想这是因为我无法访问包含该类的类加载器?
When running your annotation processor, you don't have access to the compiled classes. 运行注释处理器时,您无权访问已编译的类。 The point of annotation processing is that it happens pre-compile.
注释处理的重点是它发生在预编译之前。
Instead, you need to create an annotation processor that specifically handles your annotation type, then use the mirror API to access the field. 相反,您需要创建专门处理注释类型的注释处理器,然后使用镜像API访问该字段。 For example:
例如:
@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;
}
}
For the validation, you cannot use any classes which have yet to be compiled (including those that are about to be compiled with the annotation) using something like MyType.class
. 对于验证,您不能使用类似
MyType.class
类的任何尚未编译的类(包括那些即将使用注释编译的类)。 For these, you must use strings only . 对于这些,您必须仅使用字符串 。 That is because annotation processing occurs during a pre-compiling phase known as "source generation", which is what allows you to generate source code before the compiler runs using annotations.
这是因为注释处理在称为“源代码”的预编译阶段发生,这使得您可以在编译器使用注释运行之前生成源代码。
An example validation verifying that the field type is java.lang.String
(which is already compiled): 验证字段类型是
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);
}
}
Resources 资源
javax.lang.model
and the old API is deprecated. javax.lang.model
下javax.lang.model
并且不推荐使用旧API。 See this blog post for more information. javax
classes, then you don't need to worry. javax
类,那么您不必担心。 Edit: 编辑:
I want to get the field type to get annotations on that type.
我想获取字段类型以获取该类型的注释。 But this does not seem like it will be possible?
但这似乎不可能吗?
Indeed it is possible! 确实有可能! This can be done using more methods on the
TypeMirror
: 这可以使用
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();
From here, you have two choices: 从这里,您有两个选择:
javac
that's running the APT) then you can reference it via AnnotationMirror
instances. javac
的调用中javac
的),那么您可以通过AnnotationMirror
实例引用它。 Already Compiled 已编译
DifferentAnnotation diffAnn = fieldTypeElement.getAnnotation(
DifferentAnnotation.class);
// Process diffAnn
Very straight-forward, this gives you direct access to the annotation itself. 非常简单,这使您可以直接访问注释本身。
Not Compiled 没编译
Note that this solution will work regardless of whether or not the annotation is compiled, it's just not as clean as the code above. 请注意,无论注释是否已编译,此解决方案都将起作用,它不像上面的代码那样干净。
Here are a couple methods I wrote once to extract a certain value from an annotation mirror by its class name: 以下是我编写的一些方法,用于通过类名从注释镜像中提取某个值:
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;
}
Let's say that you're looking for the DifferentAnnotation
annotation and your source code looks like this: 假设您正在寻找
DifferentAnnotation
注释,您的源代码如下所示:
@DifferentAnnotation(name = "My Class")
public class MyClass {
@MyAnnotation
private String field;
// ...
}
This code will print My Class
: 此代码将打印
My Class
:
String diffAnnotationName = findAnnotationValue(fieldTypeElement,
"com.example.DifferentAnnotation", "name", String.class);
System.out.println(diffAnnotationName);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.