我正在编写我的第一个Annotations处理器,并且遇到一些看似微不足道的问题,但我找不到任何有关它的信息.
我有一个用我的注释注释的元素
@MyAnnotation String property;
Run Code Online (Sandbox Code Playgroud)
当我将此属性作为处理器中的元素时,我似乎无法以任何方式获取元素的类型.在这种情况下,a希望获得表示String的Class或TypeElement实例.
我尝试实例化容器类型的类对象,Class.forName()但它抛出了ClassNotFoundException.我想这是因为我无法访问包含该类的类加载器?
Bri*_*ian 55
运行注释处理器时,您无权访问已编译的类.注释处理的重点是它发生在预编译之前.
相反,您需要创建专门处理注释类型的注释处理器,然后使用镜像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;
}
}
Run Code Online (Sandbox Code Playgroud)
对于验证,您不能使用任何尚未编译的类(包括那些即将使用注释编译的类)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);
}
}
Run Code Online (Sandbox Code Playgroud)
资源
javax.lang.model旧API已弃用.有关更多信息,请参阅此博客文章.如果你一直在使用这些javax课程,那么你不必担心.编辑:
我想获取字段类型以获取该类型的注释.但这似乎不可能吗?
确实有可能!这可以使用更多方法完成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();
Run Code Online (Sandbox Code Playgroud)
从这里,您有两个选择:
javac运行APT的编译中编译),那么您可以通过AnnotationMirror实例引用它.已编译
DifferentAnnotation diffAnn = fieldTypeElement.getAnnotation(
DifferentAnnotation.class);
// Process diffAnn
Run Code Online (Sandbox Code Playgroud)
非常简单,这使您可以直接访问注释本身.
没编译
请注意,无论注释是否已编译,此解决方案都将起作用,它不像上面的代码那样干净.
以下是我编写的一些方法,用于通过类名从注释镜像中提取某个值:
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;
}
Run Code Online (Sandbox Code Playgroud)
假设您正在寻找DifferentAnnotation注释,您的源代码如下所示:
@DifferentAnnotation(name = "My Class")
public class MyClass {
@MyAnnotation
private String field;
// ...
}
Run Code Online (Sandbox Code Playgroud)
此代码将打印My Class:
String diffAnnotationName = findAnnotationValue(fieldTypeElement,
"com.example.DifferentAnnotation", "name", String.class);
System.out.println(diffAnnotationName);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10571 次 |
| 最近记录: |