5

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> ?

4
  • 1
    "fails with exception" What exception? Post the stack trace. Commented Jan 30, 2019 at 13:21
  • I don't think annotations can accept instances of Class as parameter Commented Jan 30, 2019 at 13:23
  • @Stultuske They can. Have you never written a test annotated with @RunWith(MockitoJUnitRunner.class) ? Commented Jan 30, 2019 at 13:26
  • @Michael you're right .. dumb remark of mine :) Commented Jan 30, 2019 at 13:37

1 Answer 1

4

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;
    }
Sign up to request clarification or add additional context in comments.

7 Comments

i got lambada expression not supported language level 7 syntax error . i am in the same situation except i have Class[] classes(); in my annotation parameter . could you help me with it? it's really confusing!
@lvl4fi4 You need to compile with a langauge level 8 or above , or you can replace the lambdas in my code with standard code.
never mind i fount more simple solution : stackoverflow.com/a/52793839/2979171 thanks anyway.
I would not prefer to depend on an exception to solve this problem, things might behave in a different way with different environments.
well, it's suppose to work in Source ,not runtime so, i'm fine with it for now.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.