Quarkus: ApplicationScoped inside ApplicationScoped not working with Kotlin

Created on 10 Apr 2019  路  14Comments  路  Source: quarkusio/quarkus

In my test project: https://github.com/renandeandradevaz/quarkus-kotlin

I have a Resource:
GreetingResource.kt

@Path("/greeting")
class GreetingResource {

    @Inject
    lateinit var greetingService: GreetingService

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    fun hello() = greetingService.hello()
}

one service:
GreetingService.kt

@ApplicationScoped
open class GreetingService{

    @Inject
    lateinit var greetingService2: GreetingService2

    fun hello() = greetingService2.hello()
}

another Service:
GreetingService2.kt

@ApplicationScoped
open class GreetingService2{

    fun hello() = "hello"
}

when I started the application with the command:
./mvnw compile quarkus:dev
and call the HTTP method:
curl -X GET http://localhost:8080/greeting

An error happens:

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property greetingService2 has not been initialized

how can I properly initialize this bean?

Thanks!

arearc arekotlin kinquestion

All 14 comments

Do you absolutely need @ApplicationScoped?

If not, then you could change GreetingService to:

@Singleton
open class GreetingService constructor(val greetingService2: GreetingService2){

    fun hello() = greetingService2.hello()
}

Thank you so much! This works perfectly!

You are welcome!

Hello @geoand ,
What if we really wanted to keep those two services as "@ApplicationScoped"?
Or does it mean it is not possible to inject an "@ApplicationScoped" inside another "@ApplicationScoped"?

The thing is, if we use "@Singleton" then we are no more able to use "@InjectMock" for testing.

Thank you.

Hi,

It is possible, Your best best it just use constructor injection

Thanks for your quick reply.

I tried with this:
`@ApplicationScoped
class GreetingService constructor(val greetingService2: GreetingService2){

fun hello() = greetingService2.hello() // greetingService2 is null (not injected)

}`

where GreetingService2 is also annotated @ApplicationScoped.

Any idea ?

How is GreetingService being used?

GreetingService is also injected inside the entry point class which is also annotated @ApplicationScoped like this:

@ApplicationScoped
open class Entry() {
 @Inject
  lateinit var greetingService :GreetingService 
}

Which then begs the question, how is Entry used? You see where I'm going at :)

Yes I see, Entry declares a @Produces method which is invoked directly at start up

@Produces
  fun build(): MyBean {
     greetingService.foo() // greetingService is well injected 
}

but in the next level, GreetingService2is not injected inside GreetingService

Cannot see where I am doing wrong.

Thanks.

How about writing Entry like so:

@ApplicationScoped
open class Entry() {

  @Produces
  fun build(greetingService :GreetingService): MyBean {
     greetingService.foo()
  }

}

and GreetingService like so:

@ApplicationScoped
class GreetingService(private val greetingService2: GreetingService2) {

    fun hello() = greetingService2.hello()
}

and

@ApplicationScoped
class GreetingService2 {

    fun hello() = "hello"
}

Not better, GreetingService2 still not injected inside GreetingService.

By the way, if the two services are annotated @Singleton, it works perfectly. But then it becomes hard to mock them for unit testing since you cannot use @InjectMock and the power of Mockito.
The only way for mocking is to use the old fashion way (subclass the service, annotate it as @Mock override the methods). But with this, you cannot decide when the mock class is used or not.

So this was my initial issue, and I thought using @ApplicationScoped could ease things.

Thanks.

Go ahead and open an issue please with the project that exhibits the problem and we'll take a look

issue 10771 is now created.

Thanks for you help.

Was this page helpful?
0 / 5 - 0 ratings