Using bind with generic interfaces does not work correctry
Describe the bug
When I trying to bind multiple instances to different generic interfaces I<T>, koin returns all instances of I ignoring generic type <T>
Koin module and version:
koin-core:3.5.6
Snippet or Sample project to help reproduce
interface SomeHandler<T> {
fun handle(value: T)
}
class StringsHandler: SomeHandler<String> {
override fun handle(value: String) = println(value)
}
class LocalDateTimeHandler: SomeHandler<LocalDateTime> {
override fun handle(value: LocalDateTime) = println(value.format(DateTimeFormatter.ISO_DATE_TIME))
}
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.koinApplication
import org.koin.dsl.module
import org.koin.core.module.dsl.bind
import java.time.LocalDateTime
import kotlin.test.assertTrue
import kotlin.test.*
class ConstructorDLSBindingTest {
@Test
fun test_bind_with_generic_interface() {
val koin = koinApplication {
modules(module {
singleOf(::StringsHandler) { bind<SomeHandler<String>>() }
singleOf(::LocalDateTimeHandler) { bind<SomeHandler<LocalDateTime>>() }
})
}.koin
val textHandlers: List<SomeHandler<String>> = koin.getAll<SomeHandler<String>>()
val timeHandlers: List<SomeHandler<LocalDateTime>> = koin.getAll<SomeHandler<LocalDateTime>>()
// fail, actual size is 2
assertTrue(textHandlers.size == 1)
// this will throw ClassCastException
// java.lang.String cannot be cast to java.time.LocalDateTime
textHandlers.map { it.handle("test") }
// the same, size == 2, ClassCastException java.time.LocalDateTime cannot be cast to java.lang.String
assertTrue(timeHandlers.size == 1)
timeHandlers.map { it.handle(LocalDateTime.now()) }
}
}
Same issue here.
val appModule = module {
singleOf(::MovieRepository)
singleOf(::UpdateMovieUseCase) { bind<UseCase<List<MovieDomainModel>>>() }
singleOf(::EditMovieUseCase) { bind<UseCase<EditMovieDomainModel>>() }
}
// This does not work
val updateUseCase = koinInject<UseCase<List<MovieDomainModel>>>()
// This works
//val updateUseCase = koinInject<UpdateMovieUseCase>()
val editUseCase = koinInject<UseCase<EditMovieDomainModel>>()
println(updateUseCase)
println(editUseCase)
Will both print 6478-6478 System.out I com.example.composetest.EditMovieUseCase@554e934 6478-6478 System.out I com.example.composetest.EditMovieUseCase@554e934
The issue is when not the implementation is requested but rather the abstraction (interface).
Will this be supported in future releases?
?
For now this is a limitation, but perhaps we can imagine something that can help a specific injection case.
Same problem here.
I have an app with some kind of « namespacing » concept, with use-cases in the form of :
interface SomeUseCase<T: Namespace>
// Only one implementation
class SomeUseCaseImpl<T: Namespace> (someRepository: SomeRepository<T>) : SomeUseCase<T>
I'd like to inject the correct dependencies depending on T. This doesn't work :
object Namespace1 : Namespace
object Namespace2 : Namespace
val diModule = module {
// Namespace1
singleOf(::SomeUseCaseImpl) { bind<SomeUseCase<Namespace1>() }
singleOf(::NameSpace1SomeRepositoryImpl) { bind<SomeRepository<Namespace1>>() }
// Namespace2
singleOf(::SomeUseCaseImpl) { bind<SomeUseCase<Namespace2>() }
singleOf(::NameSpace2SomeRepositoryImpl) { bind<SomeRepository<Namespace2>>() }
}
Some limitations with typeOf performances are here. Let's see between new Kotlin typeOf & next gen DSK for Koin
And this is why koin is a non-starter. Kodein does not have this limitation.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.