Closed Sarev0k closed 9 years ago
Hi!
This is not an issue of the Gradle plugin. From what I read, the code generated by Dagger 2 uses a method which is not provided by the Guava dependency it includes. Maybe @cgruber has an idea.
If it wasn't a problem with the Gradle plugin, why does Dagger 2 work when the file I mention is in the src/main/java folder?
If my understanding is correct, the classpaths are exactly the same for both JavaCompile and GroovyCompile. The JavaCompile classpath satisfies the Guava dependency just fine.
Am I missing something here?
The Gradle plugin is only responsible for making it possible to compile Groovy files in Android. Nothing more. When you move the file from src/main/groovy
to src/main/java
, then you disable joint compilation basically, so no stubs are generated and Dagger has nothing to work on. When joint compilation is on, stubs are generated, Dagger will do more work than it has to do when it just finds a Java file. And I am assuming that the stubs trigger a condition where a call to a non existing method is done. Basically I would suspect a binary incompatibility between two dependencies in Dagger, but I am not sure, hence why I asked @cgruber.
I've actually checked on the method that the Gradle output says isn't available. As far as I can tell, based on the jars that the Gradle build is pulling in, that this method is there. I've both decompiled the jar that is getting pulled down from maven, and looked at the source for that tagged version of Guava.
Is it possible that in the Groovy joint compilation mode is doing something unnatural to the Dagger annotation processor, that would cause it to think that, that method isn't there?
Also I'm curious about what you mean when you say stubs are generated in joint compilation mode? Is there a wiki or something that describes what's going on here? [Edit: Nevermind, just found the documentation, if my understanding is correct, the Groovy Compiler generates stub java files for the java compiler to compile it's sources against. In this particular sample I've linked to, I don't think this applies given that there is no groovy file in this sample). This is a pretty simple sample project, that only has Groovy compiling a java file, so I'm not sure what Groovy is doing differently here, than going straight through JavaCompile wouldn't.
Thanks for your help.
It is actually pretty simple : in order for Java to be able to "see" and "use" Java classes and the opposite, we have a problem, because one needs to be compiled before the other, and then you face a cyclic dependency (class A, written in Java, depends on class B, written in Groovy, depending itself of class C written in Java). So the solution that Groovy has put in place so far is to use joint compilation with stubs: for each Groovy class, a Java stub is generated, so that the Java compiler can do its work and recognize Java classes. Then Groovy classes are compiled normally.
The stub generation is interesting for Dagger 2 because the stubs include the annotations, so if a Groovy class is annotated with Dagger annotations, the Java stubs will include those, and Dagger will be able to process them.
The underlying error is:
java.lang.NoSuchMethodError: com.google.common.collect.Queues.newArrayDeque()Ljava/util/ArrayDeque;
at dagger.internal.codegen.InjectBindingRegistry.<init>(InjectBindingRegistry.java:68)
at dagger.internal.codegen.ComponentProcessor.init(ComponentProcessor.java:99)
Which means that during Dagger work, it is trying to use a method which doesn't exist in Guava. I can only see two reasons for this:
For 2., this could be hidden by Gradle which would select one version automatically, but the dependency report seems to say the opposite:
$ gw dependencyInsight --configuration provided --dependency guava:dependencyInsight
com.google.guava:guava:18.0
+--- com.google.auto:auto-common:1.0-SNAPSHOT
| \--- com.google.dagger:dagger-compiler:2.0-SNAPSHOT
| \--- provided
\--- com.google.dagger:dagger-compiler:2.0-SNAPSHOT (*)
(*) - dependencies omitted (listed previously)
I think it's not a missing jar because it would have failed with a class not found instead.
One last option would be that the compile classpath for Groovy doesn't include Guava, which would in turn be provided from Gradle itself. It sounds unlikely and I would expect that to be a Gradle bug, but I need to check this too.
edit: doesn't seem to be the case.
I just reproduced the issue with a pure groovy sample in a Gradle build, so I could rule out the Android build as a contributor to this failure. Sorry for presuming it was something wrong with your plugin.
I found some interesting things in the debug logs though. Here are the arguments being passed to the groovy compiler. As you can see the classpath looks in order.
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, if you look at this log line, for the compiler daemon Gradle is setting up, you'll see that it's got its own eversion of guava on the classpath:
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'
I then pulled out the Queue class from this version of guava, and ran javap on it to look at it's public interface:
$ javap -public ./com/google/common/collect/Queues.class
Compiled from "Queues.java"
public final class com.google.common.collect.Queues {
public static <E extends java/lang/Object> java.util.concurrent.ArrayBlockingQueue<E> newArrayBlockingQueue(int);
public static <E extends java/lang/Object> java.util.concurrent.ConcurrentLinkedQueue<E> newConcurrentLinkedQueue();
public static <E extends java/lang/Object> java.util.concurrent.ConcurrentLinkedQueue<E> newConcurrentLinkedQueue(java.lang.Iterable<? extends E>);
public static <E extends java/lang/Object> java.util.concurrent.LinkedBlockingQueue<E> newLinkedBlockingQueue();
public static <E extends java/lang/Object> java.util.concurrent.LinkedBlockingQueue<E> newLinkedBlockingQueue(int);
public static <E extends java/lang/Object> java.util.concurrent.LinkedBlockingQueue<E> newLinkedBlockingQueue(java.lang.Iterable<? extends E>);
public static <E extends java/lang/Comparable> java.util.concurrent.PriorityBlockingQueue<E> newPriorityBlockingQueue();
public static <E extends java/lang/Comparable> java.util.concurrent.PriorityBlockingQueue<E> newPriorityBlockingQueue(java.lang.Iterable<? extends E>);
public static <E extends java/lang/Comparable> java.util.PriorityQueue<E> newPriorityQueue();
public static <E extends java/lang/Comparable> java.util.PriorityQueue<E> newPriorityQueue(java.lang.Iterable<? extends E>);
public static <E extends java/lang/Object> java.util.concurrent.SynchronousQueue<E> newSynchronousQueue();
public static <E extends java/lang/Object> int drain(java.util.concurrent.BlockingQueue<E>, java.util.Collection<? super E>, int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
public static <E extends java/lang/Object> int drainUninterruptibly(java.util.concurrent.BlockingQueue<E>, java.util.Collection<? super E>, int, long, java.util.concurrent.TimeUnit);
public static <E extends java/lang/Object> java.util.Queue<E> synchronizedQueue(java.util.Queue<E>);
}
As you can see newArrayDeque
is nowhere to be seen.
My thought is if that compiler daemon isn't using an isolated classloader when invoking the groovy compilation, it's version of guava might be what the Dagger annotation processor is seeing.
Do you know of a way to conclusively prove or disprove that this is the problem?
Thanks!
I think I just found the smoking gun.
I just put together another sample project with a custom annotation processor that outputs all the jars in the annotation processor's classpath.
==Classes Loaded From My Annotation Processor's Classloader==
file:/Users/werickson/AndroidStudioProjects/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/AndroidStudioProjects/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.ArrayBlockingQueue com.google.common.collect.Queues.newArrayBlockingQueue(int)
public static java.util.concurrent.ConcurrentLinkedQueue com.google.common.collect.Queues.newConcurrentLinkedQueue(java.lang.Iterable)
public static java.util.concurrent.ConcurrentLinkedQueue com.google.common.collect.Queues.newConcurrentLinkedQueue()
public static java.util.concurrent.LinkedBlockingQueue com.google.common.collect.Queues.newLinkedBlockingQueue(java.lang.Iterable)
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()
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.PriorityQueue com.google.common.collect.Queues.newPriorityQueue(java.lang.Iterable)
public static java.util.PriorityQueue com.google.common.collect.Queues.newPriorityQueue()
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 from this output, it looks like the Gradle jars are leaking into the class space of the Annotation Processor.
For your reference, here's what it looks like if I place AppModule in src/main/java
:
==Classes Loaded From My Annotation Processor's Classloader==
file:/Users/werickson/AndroidStudioProjects/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
Queue is from: jar:file:/Users/werickson/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar!/com/google/common/collect/Queues.class
==Classes Loaded From Queues ClassLoader==
file:/Users/werickson/AndroidStudioProjects/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
==Queue Methods==
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 int com.google.common.collect.Queues.drain(java.util.concurrent.BlockingQueue,java.util.Collection,int,long,java.util.concurrent.TimeUnit) throws java.lang.InterruptedException
public static java.util.concurrent.ArrayBlockingQueue com.google.common.collect.Queues.newArrayBlockingQueue(int)
public static java.util.ArrayDeque com.google.common.collect.Queues.newArrayDeque()
public static java.util.ArrayDeque com.google.common.collect.Queues.newArrayDeque(java.lang.Iterable)
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.LinkedBlockingDeque com.google.common.collect.Queues.newLinkedBlockingDeque()
public static java.util.concurrent.LinkedBlockingDeque com.google.common.collect.Queues.newLinkedBlockingDeque(int)
public static java.util.concurrent.LinkedBlockingDeque com.google.common.collect.Queues.newLinkedBlockingDeque(java.lang.Iterable)
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.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.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 java.util.Deque com.google.common.collect.Queues.synchronizedDeque(java.util.Deque)
Do you think I have enough here to file a bug with the Gradle team?
Just filed a bug with the Gradle folks.
I'm closing this issue, and will be tracking it there from now on.
Thanks so much for your help!
Thanks for the update!
Hey @Sarev0k,
Is there a workaround for this issue when using Cedric's plugin until this is fixed in Gradle ( https://github.com/gradle/gradle/pull/384 )?
Seems I've been following your footsteps, but I don't know how would I disable forking for groovyCompile on Android.
You need to do the following:
androidGroovy {
options {
groovyOptions.fork = false
}
}
However, once you get past this, you're going to run into this issue.
I've got a pull request open to fix this issue, but it hasn't been merged yet. I've been told that Gradle 2.4 will be the earliest version of Gradle that this makes it into.
Edit: Ah, just saw that you already saw my pull request. Aside from using my fork of Gradle, I don't think there's an immediate work around to this problem.
Thanks for a really quick reply. I tried this snippet (could have figured it out from this repo's README.md) and that part worked. As you predicted, I also run into an issue, where stubs are not checked for annotations.
I switched to original Dagger as a last resort before abandoning Groovy... and it works. Didn't even have to disable forking.
Are you sure you're using the original dagger in static mode instead of dynamic mode?
In Gradle builds, I'd expect the annotation processor not to process annotations on groovy stubs regardless of what version of dagger you're using.
The only way you could get around that I believe is if dagger is using reflection to do dependency injection. And if that's the case, I'm not sure how much more performant it is to guice on Android.
You are correct about such setup using dynamic mode. I see no $$InjectAdapter
classes in build/
directory and there is normally plenty of them.
I'll stick to it for now and compile your fork of Gradle if there will be need for a faster startup.
Ok - I'm sorry I missed this ping - and am only getting up to speed on it now. The specific issue in play was a guava version mismatch, as com.google.common.collect.Queues.newArrayDeque. But I'd have to dig in and replicate this a bit. It is entirely possible that it works with latter daggers because there's an implicit dep on Guava at a later version, so you're getting the later version which then has this method.
I'm not sure if the issue is gradle related or a mis-configuration. If the build tool/compiler classpath is not aligned with the dagger-compiler plugin, it's entirely possible that this issue could rear its head the way it seems to above.
The issue could be fixed by shading (jar-jaring, whatever) dagger as we have with AutoValue and the like. In such a case it would have no deps conflicts (reasonable since it's a deployable binary in a sense anyway) but that would simply mean that dagger is resistant to isolation issues in your setup, but those isolation issues remain.
Hi @cgruber this was a bug with how Gradle isolates its classpath for forked builds.
There's already an issue file to fix this
I don't think jar-jaring should be necessary.
Ok - though for other reasons I plan to do it (avoiding incompatible guava versions or auto-common versions between processors, etc.)
On Tue Feb 03 2015 at 2:00:46 PM Will Erickson notifications@github.com wrote:
Hi @cgruber https://github.com/cgruber this was a bug with how Gradle isolates its classpath for forked builds.
There's already an issue file to fix this http://forums.gradle.org/gradle/topics/gradle-overrides-the-specified-guava-dependencies-with-its-own-when-running-an-annotation-processor-from-a-groovy-build
I don't think jar-jaring should be necessary.
— Reply to this email directly or view it on GitHub https://github.com/groovy/groovy-android-gradle-plugin/issues/32#issuecomment-72744460 .
(thanks though!)
On Wed Feb 04 2015 at 11:06:56 AM Christian Gruber < christianedwardgruber@gmail.com> wrote:
Ok - though for other reasons I plan to do it (avoiding incompatible guava versions or auto-common versions between processors, etc.)
On Tue Feb 03 2015 at 2:00:46 PM Will Erickson notifications@github.com wrote:
Hi @cgruber https://github.com/cgruber this was a bug with how Gradle isolates its classpath for forked builds.
There's already an issue file to fix this http://forums.gradle.org/gradle/topics/gradle-overrides-the-specified-guava-dependencies-with-its-own-when-running-an-annotation-processor-from-a-groovy-build
I don't think jar-jaring should be necessary.
— Reply to this email directly or view it on GitHub https://github.com/groovy/groovy-android-gradle-plugin/issues/32#issuecomment-72744460 .
Gradle 2.4 will ship with a fix to this issue.
It's also introducing a change that allows java annotation processors to run against Groovy stubs.
That's a great news. Thanks Will! That's one reason not to use Groovy for Android going to disappear.
Im trying to get it work (Dagger2 + Groovy) and it does not auto-generate classes (DaggerGlobalComponent):
Application:
component = DaggerGlobalComponent.builder()
.busModule(new BusModule())
.serviceModule(new ServiceModule())
.contextModule(new ContextModule(this))
.persistenceModule(new PersistenceModule(this))
.build();
build.gradle:
androidGroovy {
options {
sourceCompatibility = '1.7'
targetCompatibility = '1.7'
groovyOptions.fork = false
}
}
gradle-wrapper.properties:
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
The error:
Error:(37, 21) error: cannot find symbol variable DaggerGlobalComponent
startup failed:
Compilation failed; see the compiler error output for details.
Error:Execution failed for task ':app:compileDevelDebugGroovy'.
> Compilation failed; see the compiler error output for details.
BUILD FAILED
any ideas?
It works for me.
I've created the following demo that demonstrates it working.
Your problem is most likely caused by your DaggerGlobalComponent being named differently than you think. If it's an inner class of an Application for instance, it would be called DaggerMyApplicationName_GlobalComponent.
If you take a look at your generated java sources under build/intermediates/classes/debug/your/package/name/
, you should be able to figure out what your component is called.
@Sarev0k with your demo:
Error:Execution failed for task ':compileDebugAidl'.
> Executor Singleton not started
And on generated sources folder of my project:
BuildConfig.class
Manifest.class
Manifest$permission.class
R.class
R$anim.class
R$attr.class
R$bool.class
R$color.class
R$dimen.class
R$drawable.class
R$id.class
R$integer.class
R$layout.class
R$mipmap.class
R$plurals.class
R$raw.class
R$string.class
R$style.class
R$styleable.class
That demo works. Make sure you've modified the project.properties to point at your android SDK.
Since you don't have any generated classes it doesn't look like you've defined your dependencies on Dagger2 correctly in your build.gradle.
If you would like more help, please recreate your issue with a simple project and provide a link to a zip of it.
Here is the project, launching them you can reproduce the issue: https://github.com/FireZenk/maat
Also into MaatApplication.groovy
you can see that DaggerGlobalComponent
can't be imported
Thanks for your help
Build is failing because of this error:
/home/werickson/temp/maat/app/build/tmp/compileDevelDebugGroovy/groovy-java-stubs/org/firezenk/maat/managers/BaseActivity.java:10: error: cannot access DrawerLayoutImpl
public abstract class BaseActivity
^
class file for android.support.v4.widget.DrawerLayoutImpl not found
startup failed:
Compilation failed; see the compiler error output for details.
I don't think this is a very simple sample. Looking at the build.gradle for this package, there are a lot of moving parts, including additional plugins that are likely to introduce noise into this investigation.
Can you please reproduce this in a package that just integrates with Gradle, Groovy, Dagger2 and Android using no other plugins or dependencies? This will allow us to better isolate what your problem really is.
I've verified that the sample project I already linked you to works on multiple machines. Perhaps you should try to figure out why that sample is failing on your machine, as there might be something wrong with your setup.
The DrawerLayoutImpl
issue is "normal" for me. You just need to build the app again and it will work. Issue was also described here: https://github.com/groovy/groovy-android-gradle-plugin/issues/34
You're right, building again solved that issue. However, this project's build still fails due to a Crashalytics problem:
java.lang.IllegalArgumentException: Crashlytics found an invalid API key: CRASHLYTICS_API_KEY.
Check the Crashlytics plugin to make sure that the application has been added successfully!
Contact support@crashlytics.com for assistance.
However, I did get far enough to see that Dagger2 did generate the class that @FireZenk said was missing:
$ tree ./app/build/intermediates/classes/production/debug/org/firezenk/maat/
./app/build/intermediates/classes/production/debug/org/firezenk/maat/
├── annotations
│ └── AnnotationParser.class
├── BuildConfig.class
├── fragments
│ └── BaseFragment.class
├── MaatApplication.class
├── managers
│ ├── BaseActivity.class
│ └── MainActivity.class
├── Manifest.class
├── Manifest$permission.class
├── modules
│ ├── BusModule.class
│ ├── BusModule_ProvideEventBusFactory.class
│ ├── BusModule_ProvideEventBusFactory.java
│ ├── ContextModule.class
│ ├── ContextModule_ProvideContextFactory.class
│ ├── ContextModule_ProvideContextFactory.java
│ ├── DaggerGlobalComponent$1.class
│ ├── DaggerGlobalComponent$Builder.class
│ ├── DaggerGlobalComponent.class
│ ├── DaggerGlobalComponent.java
│ ├── GlobalComponent.class
│ ├── PersistenceModule.class
│ ├── PersistenceModule_ProvidePersistenceFactory.class
│ ├── PersistenceModule_ProvidePersistenceFactory.java
│ ├── ServiceModule$1.class
│ ├── ServiceModule.class
│ ├── ServiceModule_ProvideServiceFactory.class
│ └── ServiceModule_ProvideServiceFactory.java
├── network
│ ├── MaatService.class
│ └── TokenEntity.class
├── persistence
│ └── Persistence.class
├── R$anim.class
├── R$attr.class
├── R$bool.class
├── R.class
├── R$color.class
├── R$dimen.class
├── R$drawable.class
├── R$id.class
├── R$integer.class
├── R$layout.class
├── R$mipmap.class
├── R$string.class
├── R$styleable.class
├── R$style.class
├── utils
│ ├── DateUtils.class
│ └── Preferences.class
└── views
└── notifications
└── PushNotificationsReceiver.class
And it looks like the reason why DaggerGlobalComponent
is unable to be imported is because you're missing the import for this class.
From the above output you can see that DaggerGlobalComponent's full path is:
org.firezenk.maat.modules.DaggerGlobalComponent
However, the class that's referencing it has the path of:
org.firezenk.maat.MaatApplication
If classes aren't in the same Java package, an import is required.
Regarding crashlytics issue: you need an api_key or remove the following line on the Android Manifest:
<meta-data android:name="com.crashlytics.ApiKey" android:value="CRASHLYTICS_API_KEY"/>
Also comment lines from 30 to 35 of MaatAplication is needed.
I tried to put: import org.firezenk.maat.modules.DaggerGlobalComponent
on MaatApplication.groovy and IDE say that cannot resolve it
I tried to put: import org.firezenk.maat.modules.DaggerGlobalComponent on MaatApplication.groovy and IDE say that cannot resolve it
This is expected. Android Studio is kind of crap when it comes to its annotation processor integration.
However, building from Android Studio or command line should still work, and you shouldn't have a runtime failure when trying to use that class.
Perhaps the Dagger2 folks have some suggestions for the best way to resolve generated sources in Android Studio.
Most people use apt
instead of provided
for compile-time dependencies like dagger-compiler.
Here is some info how to set it up: https://bitbucket.org/hvisser/android-apt
I've created the a sample Gradle project to demonstrate the problem
I've uploaded logs at the --debug log level for your references.
Oddly enough, if you were to move the AndroidModule.java file form src/main/groovy to src/main/java this project compiles with no issues. I've uploaded logs at the --debug log level for this case as well.
Do you have any ideas for what might be causing this issue?
Thanks for your help.