google / dagger

A fast dependency injector for Android and Java.
https://dagger.dev
Apache License 2.0
17.45k stars 2.02k forks source link

Use Dagger2 in android library project throws `NoClassDefFoundError` at runtime #283

Closed ChrisZou closed 8 years ago

ChrisZou commented 8 years ago

I'm using dagger2 in one of my android library project. After finish the library project, I use gradle uploadArchive to upload an aar to a maven repo. then use the compile group:artifect:version@aar syntax in an app project to consume the library project. I have no problem building the app, but at runtime, it throws NoClassDefFoundError for the class MyModule_ProvideAppFactory generated by Dagger2. I figure this class is generated for the method @Provides public Application provideApp(). Yet the generated DaggerMyComponent can be found at runtime, since the exception happens inside DaggerMyComponent class. I even included the following dependencies in the app project

compile 'com.google.dagger:dagger:2.0'
compile 'javax.annotation:jsr250-api:1.0'

Yet the problem still existed. I'm pretty sure it has nothing to do with the 65K method limits problem because we have enabled multidex in the app project. Nor it has anything to do with ProGuard since I've disabled it. I'm not sure what I've been missing, or can Dagger2 be used this way?

artem-zinnatullin commented 8 years ago

Does aar of your library contain classes generated by Dagger? Looks like a problem of library packaging.

ChrisZou commented 8 years ago

@artem-zinnatullin yes, the classes are generated properly, i can see them under app/build/intermediates/exploded-aar/mygroup/myartifect/myversion/jars/classes.jar/mypackage/MyModule_ProvideAppFactory.class in the project view of my consumer app module. Yet the code somehow failed to resolve it at runtime.

artem-zinnatullin commented 8 years ago

I see that classes are generated :) Otherwise you won't be able to compile your library, but I'm not sure that generated classes included into the aar of the library.

Can you please unarchive the aar and use some dex to jar tool and then check if jar contains classes generated by Dagger?

JakeWharton commented 8 years ago

There is no dex in an aar. Just a classes.jar.

On Sun, Dec 27, 2015 at 9:28 PM Artem Zinnatullin notifications@github.com wrote:

I see that classes are generated :) Otherwise you won't be able to compile your library, but I'm not sure that generated classes included into the aar of the library.

Can you please unarchive the aar and use some dex to jar tool and then check if jar contains classes generated by Dagger?

— Reply to this email directly or view it on GitHub https://github.com/google/dagger/issues/283#issuecomment-167461474.

artem-zinnatullin commented 8 years ago

Ah, true, just a jar with resources (and other Android stuff). So, it makes task easier for @ChrisZou!

JakeWharton commented 8 years ago

His comment shows they are present in the aar, since they are in the exploded-aar of the consuming app.

digitalbuddha commented 8 years ago

Can you make a small sample app?

artem-zinnatullin commented 8 years ago

Yup. You're right (damn).

@ChrisZou what about ProGuard/etc?

ChrisZou commented 8 years ago

@artem-zinnatullin I disabled proguard and the problem still existed.

ChrisZou commented 8 years ago

@digitalbuddha Sure, I'll make one and update this issue later.

artem-zinnatullin commented 8 years ago

@ChrisZou maybe you're trying to access library code before MultiDex.install()?

Because if code is in aar, aar compiled into the app, DaggerMyComponent exists at runtime and ProGuard is turned off it looks like MultiDex can be possible cause of the problem.

ChrisZou commented 8 years ago

@artem-zinnatullin No, the app class I use extends MultiDexApplication and super.onCreate() is called before DaggerMyComponent...build().

ChrisZou commented 8 years ago

Hi all, I've made a demo of this issue, see ChrisZou/dagger2inaardemo. I think it has something to do with the way gradle works with aar. If you remove the @aar, it works all fine. @artem-zinnatullin @JakeWharton @digitalbuddha

digitalbuddha commented 8 years ago

It wasn't apt problems. adding compile 'com.google.dagger:dagger:2.0' to app build.gradle ran without error

JakeWharton commented 8 years ago

Do not append @aar to dependencies. That resolves directly to an artifact without going through transitive dependency resolution.

On Mon, Dec 28, 2015, 9:21 PM Mike Nakhimovich notifications@github.com wrote:

It wasn't apt problems. adding compile 'com.google.dagger:dagger:2.0' to app build.gradlefixed the problem.

— Reply to this email directly or view it on GitHub https://github.com/google/dagger/issues/283#issuecomment-167700930.

artem-zinnatullin commented 8 years ago

Or if you have to specify @aar you can explicitly force dependencies resolution:

compile ('groupId:artifactId:version@aar') { transitive = true }

Alternative solution: if you need to share your library only as aar you can stop publishing jar and set <packaging>aar</packaging> in pom.xml so Gradle will automatically download aar without need in explicit @aar and will do dependencies resolution.

// @ChrisZou sorry for my comments about generated code and ProGuard, I've reread your issue after sleep next day and noticed that all these details were mentioned in the initial description. My bad :(

ChrisZou commented 8 years ago

@artem-zinnatullin Don't be sorry, I updated the question after you comment so that people come later would know this. :)

ChrisZou commented 8 years ago

Hi all, I've found a solution, since out project has rules that we must use @aar and false transitivity, what I did was that I found out dagger2 depends on another dependency javax.inject:javax.inject:1. Thank @digitalbuddha for the hint. So I added both

compile 'com.google.dagger:dagger:2.0'
compile 'javax.inject:javax.inject:1'

and now it works all right. I think the NoClassDefFoundError error message was a little misleading, since the generated classes were actually there! Anyway, thank you all for your help!

JakeWharton commented 8 years ago

You should not need to explicitly specify transitive dependencies, and doing so indicates a larger problem with your build that you should resolve.

mchakkarwar commented 5 years ago

Thank you guys your comments helped me to solve same issue of dagger in library module. It is solved by adding multidex enbled in target application also added following dependency in library project; compile 'javax.inject:javax.inject:1'

Also removed @aar while adding maven dependency