I wanted to find a way to create an exception handler for Spring Webflux
, and I checked the documentation for that
I used the Kotlin code example to build the an exception Handler, but I faced several errors with.
import org.springframework.boot.autoconfigure.web.WebProperties
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler
import org.springframework.boot.web.reactive.error.ErrorAttributes
import org.springframework.context.ApplicationContext
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.RouterFunction
import org.springframework.web.reactive.function.server.RouterFunctions
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import reactor.core.publisher.Mono
@Component
class MyErrorWebExceptionHandler(errorAttributes: ErrorAttributes?, resources: WebProperties.Resources?,
applicationContext: ApplicationContext?) : AbstractErrorWebExceptionHandler(errorAttributes, resources, applicationContext) {
override fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> {
return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml)
}
private fun acceptsXml(request: ServerRequest): Boolean {
return request.headers().accept().contains(MediaType.APPLICATION_XML)
}
fun handleErrorAsXml(request: ServerRequest?): Mono<ServerResponse> {
val builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
// ... additional builder calls
return builder.build()
}
}
how this can be done?
I found out a way to do that, after spending some hours here and there.
I found out that I have to create a beam for the web properties resources
.
@Component
class Resources {
@Bean
fun webResources(): WebProperties.Resources {
return WebProperties.Resources()
}
}
Then I can create the exception handler with the suspend functions that can be used to send back the error messages.
package com.saher.testing.exception
import org.springframework.boot.autoconfigure.web.WebProperties
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler
import org.springframework.boot.web.reactive.error.ErrorAttributes
import org.springframework.context.ApplicationContext
import org.springframework.http.HttpStatus
import org.springframework.http.codec.ServerCodecConfigurer
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.*
@Component
class GlobalErrorWebExceptionHandler(
errorAttributes: ErrorAttributes,
resourceProperties: WebProperties.Resources,
applicationContext: ApplicationContext,
serverCodecConfigurer: ServerCodecConfigurer
) : AbstractErrorWebExceptionHandler(
errorAttributes,
resourceProperties,
applicationContext
) {
init {
super.setMessageWriters(serverCodecConfigurer.writers)
super.setMessageReaders(serverCodecConfigurer.readers)
}
override fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> {
return coRouter {
GET("/exception", ::exceptionHandler)
}
}
private suspend fun exceptionHandler(serverRequest: ServerRequest): ServerResponse {
return ServerResponse
.status(HttpStatus.BAD_REQUEST)
.bodyValueAndAwait(
getError(serverRequest).localizedMessage
)
}
}
of course you can make a cleaner code by separating the GlobalErrorWebExceptionHandler
from the exceptionHandler
suspend functions that will be used to handle send back the error messages.
Regards