I am migrating from Dagger 2.0.2 to Dagger 2.12 and plan to utilize dagger.android API.
My question is about migrating the test code. Currently, I have an AppModule and a TestAppModule which extends it and overrides some dependencies using #Override annotation. Here is an example:
#Module
public class TestAppModule extends AppModule {
#Override
public UserDao provideUserDao() {
return mock(UserDao.class);
}
}
Now with Dagger 2.12, if I try overriding a dependency in
TestAppModule, an error is thrown: error: #Provides methods may not be overridden in modules.
What is the recommended way of overriding and mocking some of the dependencies in a TestModule while utilizing the rest of the dependencies defined in AppModule as is?
I can post a stripped down version of my Dagger setup if people think it's necessary.
I ended up solving it by simply not annotating the TestAppModule with #Module. This achieves partial mocking.
public class TestAppModule extends AppModule {
#Override
public UserDao provideUserDao() {
return mock(UserDao.class);
}
}
Related
I have implemented dependency injection in android before using dagger 2 but, recently, I have tried to use it in a new project but I get the following error:
error: cannot find symbol
import dagger.internal.InjectedFieldSignature;
^
symbol: class InjectedFieldSignature
location: package dagger.internal/location/to/App_MembersInjector.java:30: error: cannot find symbol
Here is my Application component:
#Singleton
#Component(
modules = [
(AndroidInjectionModule::class),
(VmModule::class),
(InjectorModule::class),
]
)
interface ApplicationComponent: AndroidInjector<Application> {
#Component.Builder
interface Builder{
#BindsInstance
fun application(application: App): Builder
fun build() : ApplicationComponent
}
fun inject(home: Home)
}
Then in my App class:
class App: Application(), HasAndroidInjector {
#Inject
lateinit var anAndroidInjector: DispatchingAndroidInjector<Any>
override fun onCreate() {
super.onCreate()
DaggerApplicationComponent.builder().application(this).build().inject(this)
}
override fun androidInjector(): AndroidInjector<Any> {
return anAndroidInjector
}
}
Then the injector module:
#Module
abstract class InjectorModule {
#ContributesAndroidInjector
abstract fun bindHomeActivity(): Home
}
The following is a small excerpt of my app Gradle to show the dagger version:
implementation 'com.google.dagger:dagger-android:2.24'
implementation 'com.google.dagger:dagger-android-support:2.24'
kapt 'com.google.dagger:dagger-android-processor:2.24'
kapt 'com.google.dagger:dagger-compiler:2.28'
If you have any clue, kindly let me know where the problem might be.
Your Dagger artifact versions don't match. Specifically, you are using dagger-compiler:2.28 to generate code, but including an dependency on Dagger 2.24 instead.
In the specific case of dagger.internal.InjectedFieldSignature, that class appears to have been introduced in Dagger version 2.25.3. Any later version of the Dagger compiler will expect that InjectedFieldSignature exists and can be used in generated code. However, since you're only including Dagger 2.24 in your project, the generated code ends up referring to a class that doesn't exist.
To fix this, make sure all of your Dagger dependencies use the same version.
I am currently building a library that generates interactors so lets say this is the interactor interface
interface DeleteProductUsecase :EitherInteractor<None , None, Failure.SubmitionFailure>
This interface will be annotated with this annotation:
#WorkiUsecase(ProductRepository::class)
With annotation processing, I'm generating a class that implement the interface like this:
class Generated_AddProductUsecase #Inject constructor(couroutineDispatchers: CouroutineDispatchers, val repo: ProductRepository) : DeleteProductUseCase
And a module that will provide our interactor:
#Module abstract class WorkiModule {
#Binds
abstract fun provideGenerated_AddProductUsecase(): AddProductUsecase
}
so the problem is I need to access the module to add it to the appComponent but in compile time the module generated is not yet generated so I can't access. it
In my application, I have two modules: app and repository.
repository depends on Room, and has a GoalRepository interface:
interface GoalRepository
and a GoalRepositoryImpl class that is internal, as I don't want to expose it or the Room dependency to other modules:
#Singleton
internal class GoalRepositoryImpl #Inject constructor(private val dao: GoalDao) : GoalRepository
app depends on repository to get a GoalRepository instance.
I have a GoalRepositoryModule that, at the moment, is:
#Module
class GoalRepositoryModule {
#Provides
#Singleton
fun provideRepository(impl: GoalRepositoryImpl): GoalRepository = impl
#Provides
#Singleton
internal fun provideGoalDao(appDatabase: AppDatabase): GoalDao = appDatabase.goalDao()
#Provides
#Singleton
internal fun provideDatabase(context: Context): AppDatabase =
Room.databaseBuilder(context, AppDatabase::class.java, "inprogress-db").build()
}
The issue is that this won't compile (obviously) as the public provideRepository function is exposing GoalRepositoryImpl, that is an internal class.
How can I structure my Dagger setup to achieve what I want?
Edit:
I tried making provideRepository internal as per #David Medenjak comment and now the Kotlin compiler complains that it cannot resolve RoomDatabase dependency:
Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:
class xxx.repository.database.AppDatabase, unresolved supertypes: androidx.room.RoomDatabase
For completeness, the code of my Component inside the app module:
#Component(modules = [ContextModule::class, GoalRepositoryModule::class])
#Singleton
interface SingletonComponent
After looking at the code Dagger was generating, I understood that the mistake was making the #Component inside the app module depend on the #Module inside the repository module.
So I made a separate #Component inside the repository module and made the app module's one depend on it.
The code
The repository module's component:
#Component(modules = [GoalRepositoryModule::class])
interface RepositoryComponent {
fun goalRepository(): GoalRepository
}
The app's one:
#Component(modules = [ContextModule::class], dependencies = [RepositoryComponent::class])
#Singleton
interface SingletonComponent
This way the RepositoryComponent is responsible for building the Repository and knows all its dependencies, while the SingletonComponent only have to know about RepositoryComponent.
I'm using Dagger 2.21 and when I try to do
#Module
internal abstract class FragmentModule {
#ContributesAndroidInjector
internal abstract fun loginFragment() : LoginFragment
}
and
#Singleton
#Component(modules = [AndroidSupportInjectionModule::class, AppModule::class, ActivityModule::class, ViewModelBuilder::class, ViewModelModule::class, RepositoriesModule::class, ApiModule::class, FragmentModule::class])
interface AppComponent : AndroidInjector<PhotocoApplication> {
#Component.Builder
abstract class Builder : AndroidInjector.Builder<PhotocoApplication>()
}
I get this error:
/app/build/generated/source/kapt/debug/com/photoco/app/injection/module/FragmentModule_LoginFragment$app_debug.java:18: error: incompatible types: Class LoginFragment cannot be converted to Class extends Fragment
I have been searching and saw that using 2.21 and setting this gets it to work but no luck yet
android.useAndroidX=true ; android.enableJetifier=true
LoginFragment extends:
dagger.android.support.DaggerFragment()
With all this setup can't get it to build, am I missing something here? I can make it work with Activities using DaggerActivity but not with Fragments.
PhotocoApplication extends dagger.android.support.DaggerApplication
Thanks!
Fixed this issue by updating all dagger dependencies to 2.21, was missing android-support (was still using 2.16).
implementation 'com.google.dagger:dagger:2.21'
implementation 'com.google.dagger:dagger-android:2.21'
implementation 'com.google.dagger:dagger-android-support:2.21'
kapt "com.google.dagger:dagger-compiler:2.21"
kapt "com.google.dagger:dagger-android-processor:2.21"
I just had the same problem but with two non-Android classes: EventBus and a wrapper class around Android resources.
I tried the solution proposed by Emanuel Amiguinho even it had nothing to do with android-support and it got fixed. So I tried to remove the added dependency and retry, and magically built successfully again.
So I guess in my case it was some caching issue.
I'm newbie for Dagger.
Current I create sample project some snip code:
MyComponent.java
#PerActivity
#Component(modules = MyModule.class)
public interface MyComponent {
void inject(TutorialActivity activity);
}
MyModule.java
#Module
public class MyModule {
#Provides
Position providePosition() {
return new Position();
}
}
PerActivity.java
#Scope
#Retention(RUNTIME)
public #interface PerActivity {}
TutorialActivity.java
public class TutorialActivity extends AppCompatActivity{}
When compile project I get error:
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> java.lang.IllegalArgumentException: expected one element but was: <android.support.v4.app.FragmentActivity, android.support.v4.app.TaskStackBuilder.SupportParentable>
So if I change TutorialActivity as:
public class TutorialActivity extends Activity{}
or even
public class TutorialActivity{} // Without extends
Then it will working normally.(I can see class generated by Dagger2).
Please help !
Thanks.
UPDATE
My project structure:
common module.
app module. (app module will use common module as depended in gradle).
In both build.gradle (common and app module) I added:
apt "com.google.dagger:dagger-compiler:${daggerVersion}"
compile "com.google.dagger:dagger:${daggerVersion}"
In build.gradle at common module:
provide "org.glassfish:javax.annotation:${javaxAnnotationVersion}"
An error only occurs if I have 2 module. (module app depended on common).
If I move my Component/Module to module common -> It work.
But when I move that to app module -> Error when compile.
I'm not sure that your issue is a problem with Dagger because I don't see you requesting any dependencies in your Android components.
Nonetheless you need this in your build.gradle to use the depdendency injection annotations.
provided 'javax.annotation:jsr250-api:1.0'
Thanks #plash for your answer.
After I re-check for both module.
I found I only added:
provide "org.glassfish:javax.annotation:${javaxAnnotationVersion}"
in common module.
After I added that provide for both module then compile success.(Dagger generated class.)