How to read a Class[] values from a nested annotation in an annotation processor

爱⌒轻易说出口 提交于 2019-12-10 17:29:13

问题


I am trying to generate some code using Java annotation processing tools, I have nested annotations where the parent annotation value is an array of the child annotation, and the child annotation value is an array of classes.

Annotations:

public @interface ParentAnnotation {
    ChildAnnotation[] value();
}
public @interface ChildAnnotation {
    Class<?>[] value();
}

Usage:

@ParentAnnotation(
{
      @ChildAnnotation({Foo.class, Bar.class}),
      @ChildAnnotation({Goo.class, Doo.class})
})
public class Sample{
}

calling value() on the annotation with my Processor subtype fails with this exception:

Error:java: error while creating source file javax.lang.model.type.MirroredTypeException: Attempt to access Class object for TypeMirror org.dominokit.samples.layout.shared.extension.LayoutEvent
    at com.sun.tools.javac.model.AnnotationProxyMaker$MirroredTypeExceptionProxy.generateException(AnnotationProxyMaker.java:308)
    at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:84)
    at com.sun.proxy.$Proxy28.value(Unknown Source)
    at org.dominokit.domino.apt.client.processors.module.client.presenters.PresenterProxySourceWriter.generateFireActivationEvent(PresenterProxySourceWriter.java:238)
    at org.dominokit.domino.apt.client.processors.module.client.presenters.PresenterProxySourceWriter.asTypeBuilder(PresenterProxySourceWriter.java:64)
    at org.dominokit.domino.apt.client.processors.module.client.presenters.PresenterProxyProcessingStep.generateProxy(PresenterProxyProcessingStep.java:66)
    at org.dominokit.domino.apt.client.processors.module.client.presenters.PresenterProxyProcessingStep.process(PresenterProxyProcessingStep.java:53)
    at org.dominokit.domino.apt.client.processors.module.client.presenters.PresenterProxyProcessor.process(PresenterProxyProcessor.java:61)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
    at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)
    at com.sun.tools.javac.main.Main.compile(Main.java:523)
    at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
    at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
    at org.jetbrains.jps.javac.JavacMain.compile(JavacMain.java:196)
    at org.jetbrains.jps.incremental.java.JavaBuilder.compileJava(JavaBuilder.java:448)
    at org.jetbrains.jps.incremental.java.JavaBuilder.compile(JavaBuilder.java:318)
    at org.jetbrains.jps.incremental.java.JavaBuilder.doBuild(JavaBuilder.java:243)
    at org.jetbrains.jps.incremental.java.JavaBuilder.build(JavaBuilder.java:201)
    at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1327)
    at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:1007)
    at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:1074)
    at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:968)
    at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:797)
    at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:375)
    at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:178)
    at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:138)
    at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:302)
    at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:135)
    at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler.lambda$channelRead0$0(BuildMain.java:229)
    at org.jetbrains.jps.service.impl.SharedThreadPoolImpl.lambda$executeOnPooledThread$0(SharedThreadPoolImpl.java:42)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

so how i can read these classes from the annotation as a List<TypeMirror> ?


回答1:


After lots of debugging and trying one thing at a time i found the solution for this, the idea was in how to use the AnnotationMirror to obtain AnnotationValue, there was some sort of confusion at some point where the expected return types to be AnnotationValue[] was actually List<AnnotationValue>, below is a utility method i wrote to read the classes as a List<List<TypeMirror>> :

private List<List<TypeMirror>> getNestedAnnotationClassesValue(Element element){

        List<List<TypeMirror>> classesInAnntation = new ArrayList<>();
        if (nonNull(element.getAnnotation(ParentAnnotation.class))) {
            List<? extends AnnotationMirror> annotations = element.getAnnotationMirrors();
            for (AnnotationMirror annotationMirror : annotations) {
                if (types.isSameType(annotationMirror.getAnnotationType(), elements.getTypeElement(ParentAnnotation.class.getName()).asType())) {
                    Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = annotationMirror.getElementValues();

                    elementValues.values()
                            .stream()
                            .findFirst()
                            .ifPresent(annotationValue -> {
                                List<AnnotationMirror> childAnnotations = (List<AnnotationMirror>) annotationValue.getValue();
                                childAnnotations.stream()
                                        .forEach(childAnnotationMirror -> {
                                            Collection<? extends AnnotationValue> values = childAnnotationMirror.getElementValues()
                                                    .values();
                                            AnnotationValue childAnnotationValue = values.stream().findFirst().get();
                                            List<AnnotationValue> classesInNestedAnnotation = (List<AnnotationValue>) childAnnotationValue.getValue();
                                            Iterator<? extends AnnotationValue> iterator = classesInNestedAnnotation.iterator();

                                            List<TypeMirror> typeMirrorsInNestedAnnotation = new ArrayList<>();

                                            while (iterator.hasNext()) {
                                                AnnotationValue next = iterator.next();
                                                typeMirrorsInNestedAnnotation.add((TypeMirror) next.getValue());
                                            }

                                            if (!typeMirrorsInNestedAnnotation.isEmpty()) {
                                                classesInAnntation.add(typeMirrorsInNestedAnnotation);
                                            }
                                        });
                            });
                }
            }
        }
        return classesInAnntation;
    }


来源:https://stackoverflow.com/questions/54441572/how-to-read-a-class-values-from-a-nested-annotation-in-an-annotation-processor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!