How to read a class[] value from nested annotation in annotation processor


Ahmed Bawaneh:

I'm trying to generate some code using Java annotation processing tools, and I have nested annotations if the parent annotation value is an array of child annotations, and the child annotation value class is an array.

Notes:

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 the subtype value()with my annotation Processorfails 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 to read these courses from the notes as List<TypeMirror>?

Ahmed Bawaneh:

After a lot of debugging, and trying a thing or two at a time, I found a solution for this situation, how the idea is to use AnnotationMirrorto get AnnotationValue, there is some kind of confusion where the expected return type is AnnotationValue[]actually List<AnnotationValue>, below is a Practical method I write reading class as 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;
    }

Related


Get fields of class from annotation processor annotation object

Luke: I am working on my first annotation processor. I'm trying to get through a field (which is a method field) of the declared object on the annotated class. E.g: public class Person { private String name; private String surname; } ... public void m

Get fields of class from annotation processor annotation object

Luke: I am working on my first annotation processor. I'm trying to get through a field (which is a method field) of the declared object on the annotated class. E.g: public class Person { private String name; private String surname; } ... public void m

How to exclude annotation processor dependencies from ProGuard

Trevor A: Getting a ProGuard warning when trying to create a release version of my Android project, preventing the build from completing successfully. Warning: Library class com.google.googlejavaformat.java.filer.FormattingJavaFileObject$1$1 extends or impleme

How to call annotation processor from Gradle plugin

Auld Issa I'm currently working on a Gradle custon plugin that should analyze a specific configuration in each subproject of my root project and then generate some kotlin source code in the build directory. I can't find a way to call my annotation processor fr

How to exclude annotation processor dependencies from ProGuard

Trevor A: Getting a ProGuard warning when trying to create a release version of my Android project, preventing the build from completing successfully. Warning: Library class com.google.googlejavaformat.java.filer.FormattingJavaFileObject$1$1 extends or impleme

How to call annotation processor from Gradle plugin

Auld Issa I'm currently working on a Gradle custon plugin that should analyze a specific configuration in each subproject of my root project and then generate some kotlin source code in the build directory. I can't find a way to call my annotation processor fr

How to call annotation processor from Gradle plugin

Auld Issa I'm currently working on a Gradle custon plugin that should analyze a specific configuration in each subproject of my root project and then generate some kotlin source code in the build directory. I can't find a way to call my annotation processor fr

How to call annotation processor from Gradle plugin

Auld Issa I'm currently working on a Gradle custon plugin that should analyze a specific configuration in each subproject of my root project and then generate some kotlin source code in the build directory. I can't find a way to call my annotation processor fr

How to call annotation processor from Gradle plugin

Auld Issa I'm currently working on a Gradle custon plugin that should analyze a specific configuration in each subproject of my root project and then generate some kotlin source code in the build directory. I can't find a way to call my annotation processor fr

Read annotation value from interface?

Min Naing yes I'm working on a framework that allows developers to do database operations through a service layer. The service class will send the database request dto object which will be annotated with the sql ID to use as the ID in MyBatis. Later, I will re

Read annotation value from interface?

Min Naing yes I'm working on a framework that allows developers to do database operations through a service layer. The service class will send the database request dto object which will be annotated with the sql ID to use as the ID in MyBatis. Later, I will re

Get field class in annotation processor

Emil Sjölander: I'm writing my first annotation processor and I'm having some trivial issues, but can't find any info about it. I have an element with an annotation @MyAnnotation String property; When I get this property as an element in the processor, I can'

Get field class in annotation processor

Emil Sjölander: I'm writing my first annotation processor and I'm having some trivial issues, but can't find any info about it. I have an element with an annotation @MyAnnotation String property; When I get this property as an element in the processor, I can'

Get field class in annotation processor

Emil Sjölander: I'm writing my first annotation processor and I'm having some trivial issues, but can't find any info about it. I have an element with an annotation @MyAnnotation String property; When I get this property as an element in the processor, I can'

Get field class in annotation processor

Emil Sjölander: I'm writing my first annotation processor and I'm having some trivial issues, but can't find any info about it. I have an element with an annotation @MyAnnotation String property; When I get this property as an element in the processor, I can'

Get field class in annotation processor

Emil Sjölander: I'm writing my first annotation processor and I'm having some trivial issues, but can't find any info about it. I have an element with an annotation @MyAnnotation String property; When I get this property as an element in the processor, I can'

How to get annotation parameter in annotation processor

Hiosdra : I'm writing my own annotation processor and I'm trying to make my annotation's parameter like the code below in the procedure method: roundEnv.getElementsAnnotatedWith(annotation).forEach { val annotation = it.getAnnotation(annotation)

How to get annotation parameter in annotation processor

Hiosdra : I'm writing my own annotation processor and I'm trying to make the parameters of my annotations like the code below in the procedure method: roundEnv.getElementsAnnotatedWith(annotation).forEach { val annotation = it.getAnnotation(annotation)

How to get annotation parameter in annotation processor

Hiosdra : I'm writing my own annotation processor and I'm trying to make my annotation's parameter like the code below in the procedure method: roundEnv.getElementsAnnotatedWith(annotation).forEach { val annotation = it.getAnnotation(annotation)

How to get annotation parameter in annotation processor

Hiosdra : I'm writing my own annotation processor and I'm trying to make my annotation's parameter like the code below in the procedure method: roundEnv.getElementsAnnotatedWith(annotation).forEach { val annotation = it.getAnnotation(annotation)