Gradle causes Dagger annotation processor to crash in Groovy builds

I’ve created a sample project available here to demonstrate this problem

  1. Download the zip 2. Extract 3. ./gradlew build --stacktrace

Heres the output:

:compileJava UP-TO-DATE

:compileGroovy FAILED

FAILURE: Build failed with an exception.

  • What went wrong:

Execution failed for task ‘:compileGroovy’.

java.lang.NoSuchMethodError: com.google.common.collect.Queues.newArrayDeque()Ljava/util/ArrayDeque;

  • Try:

Run with --info or --debug option to get more log output.

  • Exception is:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ‘:compileGroovy’.

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)

at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)

at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)

at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)

at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)

at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)

at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)

at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)

at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)

at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)

at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)

at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)

at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)

at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)

at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)

at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)

at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)

at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)

at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)

at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)

at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)

at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)

at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)

at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)

at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)

at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)

at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)

at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)

at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)

at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)

at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)

at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)

at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)

at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)

at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)

at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)

at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)

at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)

at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)

at org.gradle.launcher.Main.doAction(Main.java:33)

at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)

at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)

at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)

at org.gradle.launcher.GradleMain.main(GradleMain.java:23)

at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:30)

at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:127)

at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:56)

Caused by: java.lang.RuntimeException: java.lang.NoSuchMethodError: com.google.common.collect.Queues.newArrayDeque()Ljava/util/ArrayDeque;

at com.sun.tools.javac.main.Main.compile(Main.java:469)

at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:132)

at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:42)

at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:35)

at org.gradle.api.internal.tasks.compile.ApiGroovyCompiler$2$1.compile(ApiGroovyCompiler.java:112)

at org.gradle.api.internal.tasks.compile.ApiGroovyCompiler.execute(ApiGroovyCompiler.java:122)

at org.gradle.api.internal.tasks.compile.ApiGroovyCompiler.execute(ApiGroovyCompiler.java:47)

at org.gradle.api.internal.tasks.compile.daemon.CompilerDaemonServer.execute(CompilerDaemonServer.java:53)

at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)

at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)

at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)

at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)

Caused by: java.lang.NoSuchMethodError: com.google.common.collect.Queues.newArrayDeque()Ljava/util/ArrayDeque;

at dagger.internal.codegen.InjectBindingRegistry.(InjectBindingRegistry.java:68)

at dagger.internal.codegen.ComponentProcessor.init(ComponentProcessor.java:99)

at com.sun.tools.javac.processing.JavacProcessingEnvironment$ProcessorState.(JavacProcessingEnvironment.java:517)

at com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator.next(JavacProcessingEnvironment.java:614)

at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:707)

at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1700(JavacProcessingEnvironment.java:97)

at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1029)

at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1163)

at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1108)

at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:824)

at com.sun.tools.javac.main.Main.compile(Main.java:439)

… 11 more

Looking at the debug output of this build, I suspected that the annotation processor was using the wrong version of Guava, even though as far as I could tell the classpath being passed to GroovyCompile was correct.

Here’s the classpath logs for GroovyCompile, as you can see it looks like it’s pulling in the right version of Guava, highlighted in bold:

13:05:49.734 [DEBUG] [org.gradle.api.internal.tasks.compile.NormalizingGroovyCompiler] Java compiler arguments: -d /Users/werickson/AndroidStudioProjects/PureGroovyDaggerGuavaFailureDemo/build/classes/main -g -classpath /Users/werickson/.gradle/caches/modules-2/files-2.1/javax.annotation/jsr250-api/1.0/5025422767732a1ab45d93abfea846513d742dcf/jsr250-api-1.0.jar:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger-compiler/2.0-SNAPSHOT/d021463ddfd1b5c04a4118293391418843277a78/dagger-compiler-2.0-SNAPSHOT.jar:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger/2.0-SNAPSHOT/cadd885d40b816fd98ec11c4421786024da7ca76/dagger-2.0-SNAPSHOT.jar:/Users/werickson/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.4.0-rc-1/95865a25ae70317679c0c5739baaa884a7016422/groovy-2.4.0-rc-1.jar:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.google.auto/auto-common/1.0-SNAPSHOT/42f4d366b24b3fdd56950e6cfaf0ecd141d101bf/auto-common-1.0-SNAPSHOT.jar:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.squareup/javawriter/2.5.0/81241ff7078ef14f42ea2a8995fa09c096256e6b/javawriter-2.5.0.jar:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar:/Users/werickson/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar:/Users/werickson/AndroidStudioProjects/PureGroovyDaggerGuavaFailureDemo/build/classes/main /Users/werickson/AndroidStudioProjects/PureGroovyDaggerGuavaFailureDemo/src/main/groovy/com/example/myapplication/AppModule.java

However, a little further down I saw this log output, indicating that another version of guava is being associated with the Gradle Compiler Daemon:

13:05:50.262 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process ‘Gradle Compiler Daemon 1’. Working directory: /Users/werickson/AndroidStudioProjects/PureGroovyDaggerGuavaFailureDemo Command: /Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/bin/java -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -cp /Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-base-services-2.2.1.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-core-2.2.1.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-cli-2.2.1.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-native-2.2.1.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-messaging-2.2.1.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/slf4j-api-1.7.7.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/logback-classic-1.0.13.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/logback-core-1.0.13.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/jul-to-slf4j-1.7.7.jar:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/guava-jdk5-17.0.jar org.gradle.process.internal.launcher.GradleWorkerMain ‘Gradle Compiler Daemon 1’

Gradle’s version of guava guava-jdk5-17.0.jar is missing the method that the Dagger annotation processor is complaining about.

So I wrote up another sample project with my own custom written annotation processor, to see what jars are really being utilized by annotation processors that are running in a Groovy joint compilation.

Here’s the output of that build:

$ ./gradlew build

:MyProcessor:compileJava

:MyProcessor:processResources

:MyProcessor:classes

:MyProcessor:jar

:compileJava UP-TO-DATE

:compileGroovy

==Classes Loaded From My Annotation Processor’s Classloader==

file:/Users/werickson/Downloads/PureGroovyGuavaFailureDemoWithCustomAnnotationProcessor/MyProcessor/build/libs/MyProcessor.jar

file:/Users/werickson/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.4.0-rc-1/95865a25ae70317679c0c5739baaa884a7016422/groovy-2.4.0-rc-1.jar

file:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar

file:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger/2.0-SNAPSHOT/cadd885d40b816fd98ec11c4421786024da7ca76/dagger-2.0-SNAPSHOT.jar

file:/Users/werickson/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar

file:/Users/werickson/Downloads/PureGroovyGuavaFailureDemoWithCustomAnnotationProcessor/build/classes/main/

Queue is from: jar:file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/guava-jdk5-17.0.jar!/com/google/common/collect/Queues.class

==Classes Loaded From Queues ClassLoader==

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-base-services-2.2.1.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-core-2.2.1.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-cli-2.2.1.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-native-2.2.1.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/gradle-messaging-2.2.1.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/slf4j-api-1.7.7.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/logback-classic-1.0.13.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/logback-core-1.0.13.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/jul-to-slf4j-1.7.7.jar

file:/Users/werickson/.gradle/wrapper/dists/gradle-2.2.1-bin/88n1whbyjvxg3s40jzz5ur27/gradle-2.2.1/lib/guava-jdk5-17.0.jar

==Queue Methods==

public static java.util.concurrent.PriorityBlockingQueue com.google.common.collect.Queues.newPriorityBlockingQueue(java.lang.Iterable)

public static java.util.concurrent.PriorityBlockingQueue com.google.common.collect.Queues.newPriorityBlockingQueue()

public static java.util.concurrent.ConcurrentLinkedQueue com.google.common.collect.Queues.newConcurrentLinkedQueue()

public static java.util.concurrent.ConcurrentLinkedQueue com.google.common.collect.Queues.newConcurrentLinkedQueue(java.lang.Iterable)

public static java.util.concurrent.ArrayBlockingQueue com.google.common.collect.Queues.newArrayBlockingQueue(int)

public static java.util.PriorityQueue com.google.common.collect.Queues.newPriorityQueue()

public static java.util.PriorityQueue com.google.common.collect.Queues.newPriorityQueue(java.lang.Iterable)

public static java.util.concurrent.LinkedBlockingQueue com.google.common.collect.Queues.newLinkedBlockingQueue()

public static java.util.concurrent.LinkedBlockingQueue com.google.common.collect.Queues.newLinkedBlockingQueue(int)

public static java.util.concurrent.LinkedBlockingQueue com.google.common.collect.Queues.newLinkedBlockingQueue(java.lang.Iterable)

public static java.util.concurrent.SynchronousQueue com.google.common.collect.Queues.newSynchronousQueue()

public static int com.google.common.collect.Queues.drainUninterruptibly(java.util.concurrent.BlockingQueue,java.util.Collection,int,long,java.util.concurrent.TimeUnit)

public static java.util.Queue com.google.common.collect.Queues.synchronizedQueue(java.util.Queue)

public static int com.google.common.collect.Queues.drain(java.util.concurrent.BlockingQueue,java.util.Collection,int,long,java.util.concurrent.TimeUnit) throws java.lang.InterruptedException

As you can see in the output I’m getting different results for the jars that are used based on which class I pull the classloader from. If I pull the classloader from the AnnotationProcessor’s class, I get the jars I expect.

However, if I pull the classloader from the Queues class, I see the list of jars from the Gradle Compiler Daemon.

I think this clearly shows that there is a problem with the compiler daemon linking it’s classloader into the annotation processor.

If in this example I move AppModle.java from ‘src/main/groovy’ to ‘src/main/java’ I’ll get different results. Regardless of where I pull the classloader from, I get the set of jars that I expect.

Can you guys help me file a bug for this, and get the fix prioritized from the next Gradle release? This is blocking me from writing a Groovy application that utilizes Dagger.

Thanks!

This builds fine for me. Can you please check the example project.

I’ve raised GRADLE-3220 for this. There’s an explanation of what’s going on in that description.

I can’t promise that this will be fixed for the next release. The best way to increase the chance of that happening is to contribute a fix. If you’re interested in doing this, please send an email to the dev group (https://groups.google.com/forum/#!forum/gradle-dev) and we can come up with a plan.

Thanks Luke. FWIW, this prevents usage of Dagger 2 in Groovy+Android projects, where the issue was initially reported.

I’ve just had a discussion with Daz from GradleWare, in a related news group thread, and he explained that he believed this issue was due to forking of the Groovy Compiler.

He explained that by default Java builds are not forked, but Groovy builds are.

Based on that I was able to experimentally verify that if I enable forking for Java compilation, I can reproduce this problem with Dagger. And if I disable forking in Groovy compilation I can work around this problem.

compileGroovy {

groovyOptions.fork = false

}