Skip to content

Kotlin Coroutines client impl: unable to use RequestScoped in Spring Boot due to "final" stub implementation #473

@dave-carbon

Description

@dave-carbon

We are using grpc-kotlin to generate client code in DGS, which is built on Spring Boot.

Currently we inject gRPC clients throughout our codebase with a typical Spring Boot singleton bean:

@Bean
fun someService(): SomeServiceCoroutineStub = SomeServiceCoroutineStub(...)

class Resolver(
  @Autowired private val client: SomeServiceCoroutineStub
) {
  fun field() {
    client.method()
  }
}

However we'd like to make it easy to pipe request-specific HTTP headers into our gRPC client Metadata. One obvious way to do this is with @RequestScope and javax.inject.Providers:

@RequestScope
@Bean
fun someService(): SomeServiceCoroutineStub = SomeServiceCoroutineStub(...).withInterceptors(request, stuff, here)

class Resolver(
  @Autowired private val client: Provider<SomeServiceCoroutineStub>
) {
  fun field() {
    client.get().method(...)
  }
}

Unfortunately that approach fails with the error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'client' defined in BeanDefinition defined in class path resource [.../Resolver.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class ...SomeServiceGrpcKt$SomeServiceCoroutineStub: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class ...SomeServiceGrpcKt$SomeServiceCoroutineStub

Caused by: java.lang.IllegalArgumentException: Cannot subclass final class ...SomeServiceGrpcKt$SomeServiceCoroutineStub

It looks like Spring Boot needs to be able to create a subclass to support @RequestScope, but since grpc-kotlin generates SomeServiceCoroutineStub as a final class it's failing.


I looked through the docs, but didn't find any way to customize the generated code. Would you be open to dropping final from the generated code to support a use-case like this?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions