Annotation Processing issues on modules

Jonathan Gibbons jonathan.gibbons at oracle.com
Fri Dec 6 01:22:44 UTC 2019


Forwarding to compiler-dev; dropping jdk-dev.

-- Jon


On 12/05/2019 04:01 PM, Jeremy Kuhn wrote:
> Hi,
>
> I've been working lately on an IoC/DI framework for Java 9+ which relies on
> annotation processing and code generation. I'm actually defining
> annotations on modules and I discovered couple of bugs during the
> processing of these annotations in the Java compiler.
>
> The first one is when we want to print a compilation message targeting a
> module's annotation, it exists on all versions since JDK 9. Let's say we
> have the following module descriptor:
>
>      @SampleAnnotation
>      module sampleModule {
>
>      }
>
> and a properly configured annotation processor to process the
> @SampleAnnotation, if we do:
>
>      this.processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING,
> "Module warning", element, annotationMirror);
>
> where element corresponds to the sampleModule and annotationMirror to the
> @SampleAnnotation, the compiler crash with a java.lang.AssertionError:
>
> An annotation processor threw an uncaught exception.
> Consult the following stack trace for details.
> java.lang.AssertionError
>       at jdk.compiler/com.sun.tools.javac.util.Assert.error(Assert.java:155)
>       at
> jdk.compiler/com.sun.tools.javac.tree.JCTree$Visitor.visitTree(JCTree.java:3235)
>       at
> jdk.compiler/com.sun.tools.javac.tree.JCTree$Visitor.visitModuleDef(JCTree.java:3227)
>       at
> jdk.compiler/com.sun.tools.javac.tree.JCTree$JCModuleDecl.accept(JCTree.java:2780)
>       at
> jdk.compiler/com.sun.tools.javac.model.JavacElements.matchAnnoToTree(JavacElements.java:298)
>       at
> jdk.compiler/com.sun.tools.javac.model.JavacElements.getTreeAndTopLevel(JavacElements.java:743)
>       at
> jdk.compiler/com.sun.tools.javac.processing.JavacMessager.printMessage(JavacMessager.java:108)
>       at
> jdk.compiler/com.sun.tools.javac.processing.JavacMessager.printMessage(JavacMessager.java:87)
>       at
> processor/com.example.processor.ModuleWarnProcessor.lambda$process$1(ModuleWarnProcessor.java:21)
>       at
> java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
>       at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
>       at
> java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
>       at
> java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
>       at
> java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:274)
>       at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
>       at
> java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
>       at
> java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
>       at
> java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
>       at
> java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
>       at
> java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
>       at
> java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
>       at
> java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
>       at
> processor/com.example.processor.ModuleWarnProcessor.process(ModuleWarnProcessor.java:19)
>       at
> jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:1023)
>       at
> jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:939)
>       at
> jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1267)
>       at
> jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1381)
>       at
> jdk.compiler/com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1263)
>       at
> jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:935)
>       at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:318)
>       at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:176)
>       at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:57)
>       at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:43)
>
> I've been able to track down the issue in
> com.sun.tools.javac.model.JavacElements#matchAnnoToTree(), the Vis class
> does not implement the visitModuleDef() method and as a result it is not
> possible to find module's annotations hence the AssertionError.
>
> The second issue occurs when you want to use imports in a module-info.java
> file, if you do so the file is simply ignored during annotation processing.
> This issue also exists on all versions since JDK 9. Let's say we have the
> following module descriptor:
>
>      import com.example.SampleAnnotation;
>
>      @SampleAnnotation
>      module sampleModule {
>
>      }
>
> and a properly configured annotation processor to process the
> @com.example.SampleAnnotation, the compiler simply doesn't take the module
> into account when processing annotation.
>
> I've been able to track down the issue in
> com.sun.tools.javac.processing.JavacProcessingEnvironment#getModuleInfoFiles()
>
>      private List<ModuleSymbol> getModuleInfoFiles(List<? extends
> JCCompilationUnit> units) {
>          List<ModuleSymbol> modules = List.nil();
>          for (JCCompilationUnit unit : units) {
>              if (isModuleInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE) &&
>                  unit.defs.nonEmpty() &&
>                  unit.defs.head.hasTag(Tag.MODULEDEF)) {
>                  modules = modules.prepend(unit.modle);
>              }
>          }
>          return modules.reverse();
>      }
>
> Here it is assumed that the first unit in a module descriptor has to be a
> module statement however according to the java language specification, a
> module descriptor can have import statements before (and this actually
> compiles just fine) as a result the module is not added to the list of
> modules candidates for annotation processing.
>
> I've also found another more tricky one which relates to the usage of
> deprecated module in the module providing the annotation processor: if we
> create a module which depends on a jdk deprecated module and which provides
> an annotation processor, having that module on the processor module path
> will make the compiler to return with nothing compiled, no error and no
> output. I didn't dig too much into this as this only impacts jdk9 which
> comes with deprecated modules (eg. java.se.ee), later versions don't have
> any issues for now. I've stopped my investigation in the
> java.lang.module.Resolver class line 181, deprecated modules are actually
> not resolved.
>
> I have prepared patches with jtreg tests for the first two issues on the
> repository head and I'd be happy to submit them. Please let me know if the
> description of the issues is clear enough and how we can proceed to fix
> them, I've already signed the OCA.
>
> Jeremy



More information about the jdk-dev mailing list