Search code examples
kotlinguice

Why doesn't guice requestInjection work on Kotlin object


I am new to Guice. I am trying to use requestInjection to inject the dependencies of a kotlin singleton object in this way.

APPROACH 1:

class SampleTest {

    @Test
    fun test() {
        Guice.createInjector(object: KotlinModule() {
            override fun configure() {
                requestInjection(A)
            }
        })
        assertEquals("Hello world", A.saySomething())
    }
}

object A {
    @Inject
    private lateinit var b: B

    fun saySomething(): String {
        return b.sayHello()
    }
}

class B {
    fun sayHello(): String {
        return "Hello world"
    }
}

But I am getting this error:

kotlin.UninitializedPropertyAccessException: lateinit property b has not been initialized

If I change A to a class with no-arg constructor, it works.

APPROACH 2:

class SampleTest {

    @Test
    fun test() {
        val a = A()
        Guice.createInjector(object: KotlinModule() {
            override fun configure() {
                requestInjection(a)
            }
        })
        assertEquals("Hello world", a.saySomething())
    }
}

class A {
    @Inject
    private lateinit var b: B

    fun saySomething(): String {
        return b.sayHello()
    }
}

class B {
    fun sayHello(): String {
        return "Hello world"
    }
}

Instead, if I change requestInjection to requestStaticInjection, it also works.

APPROACH 3:

class SampleTest {

    @Test
    fun test() {
        Guice.createInjector(object: KotlinModule() {
            override fun configure() {
                requestStaticInjection<A>()
            }
        })
        assertEquals("Hello world", A.saySomething())
    }
}

object A {
    @Inject
    private lateinit var b: B

    fun saySomething(): String {
        return b.sayHello()
    }
}

class B {
    fun sayHello(): String {
        return "Hello world"
    }
}

Why didn't APPROACH 1 work? Why did APPROACH 2 and APPROACH 3 work?


Solution

  • Kotlin's objects are treated as language static singletons, i.e. their initialization/instantiations happens outside the scope of the dependency injection framework.

    Therefor, when using the KotlinModule to inject an object, you have to use requestStaticInjection like in APPROACH 3, or change that object to a class, so that the Guice KotlinModule sees it as non-static, as presented in APPROACH 2

    Hope that clarifies things a bit.