micronaut-projects / micronaut-core

Micronaut Application Framework
http://micronaut.io
Apache License 2.0
6.07k stars 1.07k forks source link

BeanDefinitionInjectProcessor only runs once #1309

Closed saw303 closed 5 years ago

saw303 commented 5 years ago

In my Gradle build the Mapstruct annotation processor always runs before the one from Micronaut (io.micronaut.annotation.processing.BeanDefinitionInjectProcessor). There are 3 processing rounds.

Round 1

Mapstruct: Generates the MapperImpl Micronaut: Generates BeanDefinition classes & co. (but not seeing the MapperImpl yet)

Round 2

Mapstruct: gets called but does nothing Micronaut: gets called but does nothing since it's not supposed to run more than once. The Mapstruct mapper would be ready here for processing

Round 3

Mapstruct: gets called but does nothing Micronaut: gets called but does nothing since it's not supposed to run more than once

Due to this change in micronaut-projects/micronaut-core@4154c3a the annotation processor only runs once and does not work with any other annotation processors such as the one from Mapstruct (see https://gitter.im/micronautfw/questions?at=5c76b75de8ea143737846566).

Task List

Steps to Reproduce

  1. Create a simple Micronaut application
  2. Integration mapstruct annotation processor (as first processor) in your Gradle build
  3. Define a simple Mapstruct mapper interface such as
@Mapper(componentModel = "jsr330")
public interface MyMapper {
  String toDate(LocalDate mailing);
}
  1. Start your Micronaut application and try to get an bean instance of MyMapper

This will fail since there is no such bean.

Expected Behaviour

Tell us what should happen

Actual Behaviour

The io.micronaut.annotation.processing.BeanDefinitionInjectProcessor should run more than once in order to find the Mapstruct generated Java source code an generate Micronaut bean definitions from it.

Environment Information

I will provide a PR for this issue

saw303 commented 5 years ago

After removing the unwanted if block in the BeanDefinitionInjectProcessor I think I run into the original issue @jameskleeh mentioned.

When the BeanDefinitionInjectProcessor runs more than once I get the following exception in on the 1.0.4 code base.

io.micronaut.inject.writer.ClassGenerationException: Failed to open writer for service definition files: java.io.IOException: Output stream or writer has already been opened.
        at io.micronaut.inject.writer.AbstractClassWriterOutputVisitor.finish(AbstractClassWriterOutputVisitor.java:96)
        at io.micronaut.annotation.processing.BeanDefinitionInjectProcessor.process(BeanDefinitionInjectProcessor.java:191)
        at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)
        at org.gradle.api.internal.tasks.compile.processing.NonIncrementalProcessor.process(NonIncrementalProcessor.java:45)
        at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)
        at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.access$401(TimeTrackingProcessor.java:37)
        at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor$5.create(TimeTrackingProcessor.java:99)
        at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor$5.create(TimeTrackingProcessor.java:96)
        at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.track(TimeTrackingProcessor.java:117)
        at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.process(TimeTrackingProcessor.java:96)
        at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:972)
        at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:888)
        at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1214)
        at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1326)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1258)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:936)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:147)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
        at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:92)
        at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:50)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:36)
        at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerCallable.call(AbstractDaemonCompiler.java:86)
        at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerCallable.call(AbstractDaemonCompiler.java:74)
        at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:42)
        at org.gradle.workers.internal.WorkerDaemonServer.execute(WorkerDaemonServer.java:38)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:111)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
        at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
        at java.base/java.lang.Thread.run(Thread.java:834)
graemerocher commented 5 years ago

Yes like mentioned we have to the classes that are generated by Micronaut and ones already visited

saw303 commented 5 years ago

@graemerocher I think I found a way to make that annotation processor participate in every processing round. you find a PR linked to this issue #1339