简体   繁体   English

在注释处理器中获取没有任何注释的字段类型

[英]Getting type of field without any annotations in annotation processor

I've struggled with this for a while now, relying on various arcane casts and manipulation of toString to get it working, but there has to be a proper way of doing this.我已经为此苦苦挣扎了一段时间,依靠各种神秘的转换和 toString 的操作来使其工作,但必须有一种正确的方法来做到这一点。

I've got an annotation processor that looks like this:我有一个看起来像这样的注释处理器:

@SupportedAnnotationTypes("processor.EchoFields")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class TestProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        roundEnvironment.getElementsAnnotatedWith(EchoFields.class)
                .stream()
                .filter(e -> e.getKind() == ElementKind.CLASS)
                .map(TypeElement.class::cast)
                .forEach(this::echoFields);
        return false;
    }

    private void echoFields(TypeElement element) {
        log("Fields of class %s", element);
        element.getEnclosedElements().stream()
                .filter(e -> e.getKind() == ElementKind.FIELD)
                .map(VariableElement.class::cast)
                .forEach(this::echoField);
    }

    private void echoField(VariableElement element) {
        log("\tField %s of type %s", element.getSimpleName().toString(), element.asType().toString());
        for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
            log("\t\t%s", annotationMirror);
        }
    }

    private void log(String format, Object... parameters) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, String.format(format, parameters));
    }

}

When run on my test class that looks like this:在我的测试类上运行时,如下所示:

@EchoFields
public class Pojo {

    @TypeAnnotation
    @FieldAnnotation
    private List<String> aListOfStrings;
}

( @TypeAnnotation , and @FieldAnnotation have targets TYPE(_USE) and FIELD respectively) @TypeAnnotation@FieldAnnotation 分别具有目标TYPE(_USE)FIELD

I get the following output:我得到以下输出:

Note: Fields of class consumer.Pojo
Note:   Field aListOfStrings of type @processor.TypeAnnotation java.util.List<java.lang.String>
Note:           @processor.FieldAnnotation

Whereas what I want is this:而我想要的是:

Note: Fields of class consumer.Pojo
Note:   Field aListOfStrings of type java.util.List<java.lang.String>
Note:           @processor.TypeAnnotation
Note:           @processor.FieldAnnotation

With the important part being java.util.List<java.lang.String> without @processor.TypeAnnotation - Listing @processor.TypeAnnotation with the annotations is just a bonus and not something I need .重要的部分是java.util.List<java.lang.String>没有@processor.TypeAnnotation - 列出带有注释的@processor.TypeAnnotation只是一个奖励,而不是我需要的东西。

I can't seem to find any way of doing this though.我似乎无法找到任何方法来做到这一点。 Every time I find something that removes the annotation I also lose the type parameters ( java.lang.String ).每次我发现删除注释的内容时,我也会丢失类型参数( java.lang.String )。 I've poked around in the classes implementing the annotation processing API and there is definitely methods there that do what I want - but I can't find any way of invoking them through the public API and I don't want to rely on implementation details (especially since I got vastly different implementations when I tried this on JDK 8).我已经在实现注释处理 API 的类中闲逛,那里肯定有方法可以做我想做的事 - 但我找不到任何通过公共 API 调用它们的方法,我不想依赖实现细节(尤其是因为我在 JDK 8 上尝试这个时得到了截然不同的实现)。

There's a runnable Gradle project at https://github.com/Raniz85/processor-test , just clone and run ./gradlew buildhttps://github.com/Raniz85/processor-test有一个可运行的 Gradle 项目,只需克隆并运行./gradlew build

Since TypeAnnotation is marked as TYPE+TYPE_USE (and note that TYPE isn't relevant for this issue) and not FIELD, it isn't an annotation on the field at all, but is actually on the declared type of the field.由于TypeAnnotation被标记为 TYPE+TYPE_USE(并注意 TYPE 与此问题无关)而不是 FIELD,因此它根本不是字段上的注释,而实际上是字段的声明类型。 You can put TYPE_USE annotations on other things as well, like local variables - but you cannot read them from a normal annotation processor.您也可以将 TYPE_USE 注释放在其他事物上,例如局部变量 - 但您无法从普通的注释处理器中读取它们。 From How to access TypeUse annotation via AnnotationProcessor :如何通过 AnnotationProcessor 访问 TypeUse 注释

The TYPE_USE annotations are a bit tricky, because the compiler treats them differently, than the "old usage" annotations. TYPE_USE 注释有点棘手,因为编译器对待它们的方式与“旧用法”注释不同。

So as you correctly observed, they are not passed to annotation processor, and your process() method will never receive them.因此,正如您正确观察到的那样,它们不会传递给注释处理器,并且您的 process() 方法将永远不会收到它们。

Without knowing specifically what problem you are trying to solve, it is hard to say if you actually want TYPE_USE in the first place, or if you are just experimenting with the different possible targets that an annotation may have.在不知道您要解决的具体问题的情况下,很难说您是否真的想要 TYPE_USE ,或者您是否只是在尝试注释可能具有的不同可能目标。 Probably you just want to use FIELD instead here, since you are writing an annotation processor (which traverses your API, and not the source code itself, so you'll miss any TYPE_USE on local vars, etc).可能你只是想在这里使用 FIELD ,因为你正在编写一个注释处理器(它遍历你的 API,而不是源代码本身,所以你会错过本地变量上的任何 TYPE_USE 等)。

-- ——

Also, be very careful of using TypeMirror.toString() or Element.toString(), in some environments these will not output what you are expecting.此外,使用 TypeMirror.toString() 或 Element.toString() 时要非常小心,在某些环境中,这些不会输出您期望的内容。 Either use the Name type, or something like javapoet's TypeName hierarchy.要么使用 Name 类型,要么使用类似 javapoet 的 TypeName 层次结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM