Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MyErrorWebExceptionHandler example in documentation isn't working #38104

Closed
SaherAlSous opened this issue Oct 29, 2023 · 2 comments
Closed

MyErrorWebExceptionHandler example in documentation isn't working #38104

SaherAlSous opened this issue Oct 29, 2023 · 2 comments
Assignees
Labels
type: documentation A documentation update
Milestone

Comments

@SaherAlSous
Copy link

SaherAlSous commented Oct 29, 2023

Dear Spring Team,
Hope that you are doing very well.
I was reading your documentation to learn about exception handling in Reactive Web, and I tried to apply the example code that you provided in Kotlin but i faced several problems

https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/web.html#web.reactive.webflux.error-handling

I worked on my own to make it work, at the end I found out how to do it, and I thought it would be a good idea if you would like to update the code.

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
            )
    }

}

also you need to add this bean in the configuration

import org.springframework.boot.autoconfigure.web.WebProperties
import org.springframework.context.annotation.Bean
import org.springframework.stereotype.Component

@Component
class Resources {

    @Bean
    fun webResources(): WebProperties.Resources {
        return WebProperties.Resources()
    }

}

I created a stackoverflow post for it over here

https://stackoverflow.com/questions/77383331/spring-webflux-reactive-error-handling-kotlin

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 29, 2023
@mhalbritter mhalbritter changed the title Updating Kotlin code for 2.1.7. Error Handling MyErrorWebExceptionHandler example in documentation isn't working Oct 30, 2023
@mhalbritter mhalbritter added type: documentation A documentation update and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 30, 2023
@mhalbritter mhalbritter added this to the 2.7.x milestone Oct 30, 2023
@mhalbritter
Copy link
Contributor

mhalbritter commented Oct 30, 2023

Thanks for letting us know. However, I think the @Bean method in your fix isn't the right way.

Here's the Java Code that's working:

@Component
public class MyErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

    public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties,
                                      ApplicationContext applicationContext, ServerCodecConfigurer serverCodecConfigurer) {
        super(errorAttributes, webProperties.getResources(), applicationContext);
        setMessageReaders(serverCodecConfigurer.getReaders());
        setMessageWriters(serverCodecConfigurer.getWriters());
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml);
    }

    private boolean acceptsXml(ServerRequest request) {
        return request.headers().accept().contains(MediaType.APPLICATION_XML);
    }

    public Mono<ServerResponse> handleErrorAsXml(ServerRequest request) {
        ServerResponse.BodyBuilder builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR);
        // ... additional builder calls
        return builder.build();
    }

}

@mhalbritter
Copy link
Contributor

That would be the Kotlin equivalent:

@Component
class MyErrorWebExceptionHandler(
    errorAttributes: ErrorAttributes, webProperties: WebProperties,
    applicationContext: ApplicationContext, serverCodecConfigurer: ServerCodecConfigurer
) : AbstractErrorWebExceptionHandler(errorAttributes, webProperties.resources, applicationContext) {

    init {
        setMessageReaders(serverCodecConfigurer.readers)
        setMessageWriters(serverCodecConfigurer.writers)
    }

    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()
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation A documentation update
Projects
None yet
Development

No branches or pull requests

3 participants