Suppose I have the following application with a WebFilter
and I'm trying to pass some context back from the controller into the filter.
@RestController
class MyController {
@PostMapping("/test")
suspend fun postSomething(): ResponseEntity<Unit> {
val valueFromFilter = coroutineContext[ReactorContext.Key]?.context?.get<String>("myKey") ?: "EMPTY"
logger.info { "Inside handler = $valueFromFilter" } // this works since Reactor populate coroutineContext with respective ReactorContext
coroutineContext[ReactorContext.Key]?.context?.put("handlerKey", "hello")
return ResponseEntity.ok().build()
}
}
@Component
class MyFilter : WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
logger.info { "Before" }
return chain.filter(exchange)
.contextWrite(Context.of("myKey", "myValue"))
.doOnEach {
val valueFromHandler = if (it.contextView.hasKey("handlerKey")) it.contextView.get<String>("handlerKey") else "EMPTY"
logger.info { "After handler = $valueFromHandler" } // But this doesn't work since Reactor doesn't restore ReactorContext from respective coroutineContext
}
}
}
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
run(MyApplication::class.java, *args)
}
In this example if we made a request to /test
it would print the following
Before
Inside handler = myValue
After handler = EMPTY
I understand that when we call chain.filter(exchange)
to proceed with the request and the handler is a Kotlin suspend
function the framework fills in coroutineContext
with ReactorContext.Key to actualReactorContext
. Although my question is why doesn't Spring restore the context that I may have filled in the controller back, so I can use it after calling chain.filter(exchange)
. Moreover if there is anyway possible to do this currently.