2

We recently upgraded our Spring Reactive APIs that were running on Java 11 and Spring 2.7.x. Exceptions in the Controller layer are handled by a Global Exception Handler which also handled the Method Not Supported exception. Post the upgrade, we are getting internal server error instead of Method not allowed exception when we try a different HTTP verb other that the one that a specific endpoint is designated to.

Our application has both of the below dependencies:

  • spring-boot-starter-web
  • spring-boot-starter-webflux

Searched for some stack overflow links and tried adding the below piece of code but didn't help either.

@Component
@Order(-2)
public class RestWebExceptionHandler implements ErrorWebExceptionHandler {

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (ex instanceof HttpRequestMethodNotSupportedException) {
            exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

            // marks the response as complete and forbids writing to it
            return exchange.getResponse().setComplete();
        }
        return Mono.error(ex);
}

@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<PlanResponse> handleHttpRequestMethodNotSupportedException(
            final HttpRequestMethodNotSupportedException exception) {
        return responseBuilderRegistry.getResponseBuilderByType(HttpRequestMethodNotSupportedResponseBuilder.class)
                .buildResponse(exception);
    
  • Can you please provide more info about your implementation? Do you have any more handlers besides the MethodNotAllowedException? And could this be due to the order precedence? – Gabriel Magalhães Jan 28 '23 at 22:01

2 Answers2

0

That was a common issue that was "recently" addressed on Spring MVC and Spring Webflux.

If you are interested in it, this issue was discussed here https://github.com/spring-projects/spring-framework/issues/22991

Just created a project to test this, can you please try the following

@RestControllerAdvice
public class GlobalExceptionHandler {
   
   @ExceptionHandler(MethodNotAllowedException.class)
   @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
   public Mono<Void> handle(Exception e, ServerWebExchange exchange) {
      return exchange.getResponse().setComplete();
   }

}
  • Thank you. As mentioned in the issue that you have shared, it could be due to an order of precedence. But this was working back when we were using Java 11 with Spring Boot 2.7.x. Updated the exception handler in the original post. – theFlyingRaijin04 Jan 30 '23 at 03:00
0

If you use Spring WebFlux the Validation exception raised is WebExchangeBindException not MethodNotAllowedException.

Example code (Kotlin):

@RestControllerAdvice
class ValidationExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    @ExceptionHandler
    fun handleWebExchangeBindException(
        ex: WebExchangeBindException
    ): ValidationErrorResponse {
        val result = ex.bindingResult
        return ValidationErrorResponse(buildValidationErrors(result.fieldErrors))
    }

    private fun buildValidationErrors(violations: List<FieldError>): List<ValidationError> {
        return violations.map { violation ->
            ValidationError(
                field = violation.field,
                message = violation.defaultMessage ?: "${violation.field} is invalid",
            )
        }
    }
}
Japu_D_Cret
  • 632
  • 5
  • 18