This repository was archived by the owner on Aug 20, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 44
This repository was archived by the owner on Aug 20, 2025. It is now read-only.
Subcomponent + BindsInstance doesn't work #212
Copy link
Copy link
Open
Description
I'm trying to use the library in an application that uses dagger to create Worker's for WorkManager(you can find many articles about it ).
Here's the code and a test case that mimics worker injection:
package foo
import dagger.*
import dagger.multibindings.IntoMap
import org.junit.Test
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Scope
import javax.inject.Singleton
import kotlin.reflect.KClass
import kotlin.test.assertEquals
//root component
@Component(
modules = [
WorkerFactoryModule::class,
FeatureModule::class
]
)
@Singleton
interface RootComponent {
val daggerWorkerFactory: DaggerWorkerFactory
}
//worker extension point implementation
abstract class ListenableWorker(val workerParameters: String)
@Target(AnnotationTarget.FUNCTION)
@Retention
@MapKey
annotation class WorkerKey(val value: KClass<out ListenableWorker>)
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class WorkerScope
@Module(subcomponents = [WorkerFactoryComponent::class])
abstract class WorkerFactoryModule
@Subcomponent
//@WorkerScope
interface WorkerFactoryComponent {
fun workerFactories(): Map<Class<out ListenableWorker>, Provider<ListenableWorker>>
@Subcomponent.Factory
interface Factory {
fun create(@BindsInstance workerParameters: String): WorkerFactoryComponent
}
}
//worker factory
@Singleton
class DaggerWorkerFactory @Inject constructor(
private val factory: WorkerFactoryComponent.Factory
) {
fun createWorker(
workerClassName: String,
workerParameters: String
): ListenableWorker {
val workers = factory
.create(workerParameters)
.workerFactories()
val workerClass = Class
.forName(workerClassName)
.asSubclass(ListenableWorker::class.java)
val worker = workers.getValue(workerClass).get()
return worker
}
}
//feature worker implementation
@Module
abstract class FeatureModule {
@Binds @IntoMap @WorkerKey(FeatureWorker::class) abstract fun impl(w: FeatureWorker): ListenableWorker
}
//@WorkerScope
class FeatureWorker @Inject constructor(workerParameters: String) : ListenableWorker(workerParameters)
//test
class DaggerWorkerTest {
@Test
fun testWorkerInjection() {
val component = dagger.reflect.DaggerReflect.create(RootComponent::class.java)
// val component = DaggerRootComponent.create()
val daggerWorkerFactory = component.daggerWorkerFactory
val featureWorker = daggerWorkerFactory.createWorker(
workerClassName = FeatureWorker::class.java.name,
workerParameters = "foo"
)
assertEquals("foo", featureWorker.workerParameters)
}
}
Running the test gives the following error:
java.lang.IllegalStateException: Missing binding for java.lang.String
* Requested: foo.FeatureWorker
from @Inject[foo.FeatureWorker.<init>(…)]
* Requested: java.lang.String
which was not found.
If you uncomment 2 lines with //@WorkerScope, you'll get a different(and incorrect) error about invalid scopes:
java.lang.IllegalStateException: Unable to find binding for key=foo.FeatureWorker with linker=Linker with Scope[@javax.inject.Singleton()]
Note that both cases work as expected with dagger codegen.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels