Due to some changes in upstream dependencies I recently had to upgrade a project from Java 11 to Java 17. The project makes heavy use of annotation-driven code generation, and since the upgrade I'm getting a strange exception that I can't wrap my head around:
java.lang.annotation.AnnotationTypeMismatchException: Incorrectly typed data found for annotation element public abstract pro.projo.interfaces.annotation.Options pro.projo.interfaces.annotation.Interface.options() (Found data of type pro.projo.interfaces.annotation.Options)
at com.sun.tools.javac.model.AnnotationProxyMaker$ValueVisitor$1AnnotationTypeMismatchExceptionProxy.generateException (AnnotationProxyMaker.java:271)
at sun.reflect.annotation.AnnotationInvocationHandler.invoke (AnnotationInvocationHandler.java:89)
at jdk.proxy4.$Proxy31.options (Unknown Source)
at pro.projo.generation.interfaces.InterfaceTemplateProcessor.lambda$getInterfaceConfiguration$5 (InterfaceTemplateProcessor.java:268)
at java.util.stream.ReferencePipeline$3$1.accept (ReferencePipeline.java:197)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining (ArrayList.java:1625)
at java.util.stream.AbstractPipeline.copyInto (AbstractPipeline.java:509)
at java.util.stream.AbstractPipeline.wrapAndCopyInto (AbstractPipeline.java:499)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential (ReduceOps.java:921)
at java.util.stream.AbstractPipeline.evaluate (AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect (ReferencePipeline.java:682)
at pro.projo.generation.interfaces.InterfaceTemplateProcessor.getInterfaceConfiguration (InterfaceTemplateProcessor.java:379)
at pro.projo.generation.interfaces.InterfaceTemplateProcessor.process (InterfaceTemplateProcessor.java:185)
at pro.projo.generation.interfaces.InterfaceTemplateProcessor.process (InterfaceTemplateProcessor.java:162)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor (JavacProcessingEnvironment.java:1023)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs (JavacProcessingEnvironment.java:939)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run (JavacProcessingEnvironment.java:1267)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing (JavacProcessingEnvironment.java:1382)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations (JavaCompiler.java:1234)
The baffling part is that the expected type and the type that was actually found are in fact identical (they're both pro.projo.interfaces.annotation.Options
).
To maximize compatibility, the annotation processing library itself is written in Java 8 (and uses @SupportedSourceVersion(RELEASE_8)
and ElementScanner8
, accordingly), but it worked fine in Java 9 and Java 11 projects (as one would expect).
Outside of annotation processing, when I see exceptions (e.g., ClassCastException
s) that seemingly complain about the correct type, my first instinct is to check class loader issues (i.e., same type, but loaded by different class loaders). Is there a similar scenario with annotation processors?
Switching back to Java 11 makes the problem go away, but unfortunately that's not a permanent solution.
Any ideas how to further debug this?
Whereas I cannot be 100% certain and only could spend a limited amount of time on this issue, all indications are pointing indeed to JDK bug 8322706 being at the root of the observed exception. I was able to verify that the bug did not occur with Java 8 (Zulu 8.64.0.19-CA-macosx, build 1.8.0_345-b01), Java 11 (GraalVM CE 20.1.0, build 11.0.7+10-jvmci-20.1-b02), and Java 14 (Oracle JDK 14, build 14.0.2+12-46). However, it did occur when using Java 17 (GraalVM CE 22.1.0, build 17.0.3+7-jvmci-22.1-b06; Zulu 17.48+15-CA, build 17.0.10+7-LTS) and Java 21 (GraalVM 21.0.2+13.1, build 21.0.2+13-LTS-jvmci-23.1-b30). This is consistent with what is reported in the bug description (except for the fact that Java 14 is not affected, which is new information).
The bug lists three different work-arounds, and the third one (adding/repeating explicit default values for all attributes in the annotation's definition) resolved the problem right away. The second work-around (redundantly importing the annotation that is used for the primary annotation's attribute value), incongruously and against my IDE's warnings about unnecessary imports, also resolved the issue. I did not try the first work-around (explicitly adding all default values in the annotated classes), as it would have involved too many code changes.
So, in as far as I was able to verify it, the information in the bug report matches my situation.
As far as debugging is concerned, the debug run (once it was finally set up properly), did not yield too much information without putting a lot of additional effort in it. As the stack trace already indicates, the annotation object in question is a proxy object, and consequently there is no source code. I was manually able to locate the source code for the responsible InvocationHandler
, but the bottom line was that an attribute map that should have contained the attribute value contained an exception-throwing stand-in instead. As far as I could trace it back, the original problem was that another object, also represented by a proxy, did not have the expected type, most likely due to the same class being loaded twice by different class loaders.
As @Holger pointed out in the comments, using runtime types at compile time is problematic for obvious reasons (though it apparently works in most cases, and I never thought twice about it, until now). It's going to be interesting to see how bug 8322706 will be resolved eventually.