【问题标题】:Spring Framework swallows exception of custom convertersSpring Framework 吞下自定义转换器的异常
【发布时间】:2017-09-26 12:09:44
【问题描述】:

我遇到了 Spring(和 kotlin?)的问题,我的全局错误处理程序无法捕获自定义转换器中引发的任何异常。

我知道spring默认支持string->UUID映射,但我想明确检查是否真的抛出了异常。它是以下转换器。无论有没有我自己实现的转换器,行为都是相同的。

我的 WebMvcConfiguration 如下所示:

@Configuration
class WebMvcConfiguration : WebMvcConfigurerAdapter() {

    override fun addFormatters(registry: FormatterRegistry) {
        super.addFormatters(registry)
        registry.addConverter(Converter<String, UUID> { str ->
            try {
                UUID.fromString(str)
            } catch(e: IllegalArgumentException){


         throw RuntimeException(e)
        }
    })
}

这是我的 GlobalExceptionHandler: (它还包含其他处理程序,为简洁起见,我省略了)

@ControllerAdvice
class GlobalExceptionHandler : ResponseEntityExceptionHandler() {

    @ExceptionHandler(Exception::class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    fun handleException(ex: Exception): ApiError {
        logger.info(ex.message, ex)
        return ApiError(ex.message)
    }
}

最后是控制器:

@Controller
class MyController : ApiBaseController() {
    @GetMapping("/something/{id}")
    fun getSomething(@PathVariable("id") id: UUID) {
        throw NotImplementedError()
    }
}

控制器内部的异常(例如 NotImplementedError)方法被很好地捕获。但是当传递无效的 UUID 时,转换器内抛出的 IllegalArgumentException 被吞下,spring 返回一个空的 400 响应。

我现在的问题是:如何捕获这些错误并使用自定义错误消息进行响应?

提前致谢!

【问题讨论】:

  • 非常感谢您解释反对票的用途。

标签: spring spring-mvc kotlin


【解决方案1】:

我遇到了同样的问题。 Spring 吞下了任何IllegalArgumentException(在我的情况下为ConversionFailedException)。

获得我正在寻找的行为;即只处理列出的异常并使用其他异常的默认行为,你不能扩展ResponseEntityExceptionHandler

例子:

@ControllerAdvice
public class RestResponseEntityExceptionHandler{

    @ExceptionHandler(value = {NotFoundException.class})
    public ResponseEntity<Object> handleNotFound(NotFoundException e, WebRequest request){
        return new ResponseEntity<>(e.getMessage(), new HttpHeaders(), HttpStatus.NOT_FOUND);
    }

}

【讨论】:

  • 谢谢!扩展 ResponseEntityExceptionHandler 也是我的问题。删除它解决了问题。
  • 我认为值得一提的是,它将所有异常转换为 500 的 HTTP 代码,这是人们并不总是想要的。
【解决方案2】:

我检查了@georg-moser 的解决方案。起初,它看起来不错,但看起来它包含另一个问题。它将所有异常都转换为 500 的 HTTP 代码,这是人们并不总是想要的。

相反,我决定从ResponseEntityExceptionHandler 覆盖handleExceptionInternal 方法。

在我的情况下,记录错误就足够了,所以我最终得到以下结果:

@Override
@NonNull
protected ResponseEntity<Object> handleExceptionInternal(@Nonnull final Exception e,
                                                         final Object body,
                                                         final HttpHeaders headers,
                                                         final HttpStatus status,
                                                         @Nonnull final WebRequest request) {
    final ResponseEntity<Object> responseEntity = super.handleExceptionInternal(e, body, headers, status, request);
    logGenericException(e);
    return responseEntity;
}

希望对你有帮助!

【讨论】:

    【解决方案3】:

    经过反复试验,我找到了解决方案:

    代替使用@ControllerAdvice,实现其他人继承的BaseController并在那里添加异常处理程序是可行的。

    所以我的 Base 控制器看起来像这样:

    abstract class ApiBaseController{
    
        @ExceptionHandler(Exception::class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        @ResponseBody
        fun handleException(ex: Exception): ApiError {
            return ApiError(ex.message)
        }
    
    }
    

    如果有人可以详细说明为什么它会这样而不是其他方式,请这样做,我会将您的答案标记为已接受。

    【讨论】:

      猜你喜欢
      • 2012-06-22
      • 1970-01-01
      • 2016-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      • 2017-04-20
      相关资源
      最近更新 更多