-
-
Notifications
You must be signed in to change notification settings - Fork 66
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Hi,
kotlin-inject currently doesn't allow scoping suspending provider method.
@Provides
@NetworkScope
protected suspend fun api(service: Service): Api = service.connect()
Expectation: scoped suspending provider should create a single instance of the returned object.
Observation: Adding scope to suspending provider method causes compilation to fail with error: "Suspension functions can be called only within coroutine body" & removing the scope passes compilation but creates new object on every invocation.
Below is the failing test for the same:
import kotlinx.coroutines.runBlocking
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Inject
import me.tatarka.inject.annotations.Provides
import me.tatarka.inject.annotations.Scope
import org.junit.jupiter.api.Test
import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertEquals
@Scope
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER)
annotation class NetworkScope
@Component
@NetworkScope
internal abstract class NetworkComponent(@get:Provides protected val apiInstanceCounter: AtomicInteger) {
@NetworkScope
abstract suspend fun api(): Api
@Provides
// Note: Uncommenting below gives error: Suspension functions can be called only within coroutine body
// @NetworkScope
protected suspend fun api(service: Service): Api = service.connect()
protected val DummyNetworkService.bind: Service
@Provides get() = this
}
interface Api
interface Service {
suspend fun connect(): Api
}
@Inject
class DummyNetworkService(private val apiInstanceCounter: AtomicInteger) : Service {
override suspend fun connect(): Api {
apiInstanceCounter.incrementAndGet()
return object : Api {}
}
}
internal class KotlinInjectTest {
@Test
fun `calling scoped suspending provider should create singleton instance`() {
val apiInstanceCounter = AtomicInteger(0)
val networkComponent = NetworkComponent::class.create(apiInstanceCounter)
runBlocking {
val apiInstance0 = networkComponent.api()
val apiInstance1 = networkComponent.api()
assertEquals(apiInstance0, apiInstance1)
}
}
}
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working