为了账号安全,请及时绑定邮箱和手机立即绑定

在ControllerAdvice之前捕获反序列化异常

在ControllerAdvice之前捕获反序列化异常

qq_遁去的一_1 2021-04-15 18:09:42
这是一个问题:我有一个采用输入模型的控制器。可以说public class AppUserUpdateData {  @NotNull  @Size(min = 1, max = 50)  protected String login;    @JsonDeserialize(using = MyDateTimeDeserializer.class)    protected Date startWorkDate;  *************  other properties and methods  *************}问题是,当我想限制日期下降时,尽管我在代码中处理了这种情况,但最终还是得到了HTTP异常400而没有任何消息!这是一个控制器: @RequestMapping(      value = "/users/{userId}", method = RequestMethod.PUT,      produces = MediaType.APPLICATION_JSON_UTF8_VALUE)  public @ResponseBody AbstractSuccessResult updateUser(@PathVariable Long userId,      @RequestBody AppUserUpdateData  appUserUpdateRequest, HttpServletRequest request) {        AbstractSuccessResult response = new AbstractSuccessResult();    appUserService.updateUser(appUserUpdateRequest, userId);    return response;  }这是一个反序列化器:public class MyDateTimeDeserializer extends JsonDeserializer<Date> {  @Override  public Date deserialize(JsonParser jsonParser, DeserializationContext context)      throws IOException, JsonProcessingException {    try {      return DataTypeHelper.stringToDateTime(jsonParser.getText());    } catch (MyOwnWrittenException ex) {      throw ex;    }  }  }其中DataTypeHelper.stringToDateTime有一些验证阻止了无效的日期字符串。还有一个我的例外处理程序:@ControllerAdvicepublic class MyExceptionHandler extends ResponseEntityExceptionHandler {  @ExceptionHandler({ MyOwnWrittenException .class})  protected ResponseEntity<Object> handleInvalidRequest(RuntimeException exc,     WebRequest request) {    MyOwnWrittenException ex = (MyOwnWrittenException) exc;    BasicErrorMessage message; = new BasicErrorMessage(ex.getMessage());        AbstractUnsuccessfulResult result = new AbstractUnsuccessfulResult(message);    HttpHeaders headers = new HttpHeaders();    headers.setContentType(MediaType.APPLICATION_JSON);    return handleExceptionInternal(exc, result, headers, HttpStatus.BAD_REQUEST, request);  }}问题是,当MyDateTimeDeserializer引发了一个例外时,它不会陷入一个例外,MyExceptionHandler但我不明白为什么?我究竟做错了什么?在响应中只是一个空的响应,代码为400(
查看完整描述

1 回答

?
湖上湖

TA贡献2003条经验 获得超2个赞

在updateUser调用控制器之前,必须先解析其参数。这是HandlerMethodArgumentResolverComposite进入的地方,并委托给一个预注册的HandlerMethodArgumentResolvers-在这种情况下,它委托给RequestResponseBodyMethodProcessor。


通过委派,我的意思是调用解析器的resolveArgument方法。此方法deserialize从反序列化器中间接调用该方法,该方法引发type异常MyOwnWrittenException。问题在于此异常被包装在另一个异常中。实际上,当它传播回时resolveArgument,它就是type HttpMessageNotReadableException。


因此,MyOwnWrittenException您需要捕获type的异常,而不是捕获自定义异常处理程序HttpMessageNotReadableException。然后,在处理这种情况的方法中,您可以检查是否MyOwnWrittenException确实存在“原始”异常-您可以通过重复调用该getCause方法来做到这一点。就我而言(可能与您的情况相同),我需要调用getCause两次以“解包”原始异常(HttpMessageNotReadableException-> JsonMappingException-> MyOwnWrittenException)。


请注意,您不能在异常处理程序中简单地用替换MyOwnWrittenException,HttpMessageNotReadableException因为它在运行时与专门设计用于处理后一种类型的异常(称为)的另一种方法发生冲突(在运行时)handleHttpMessageNotReadable。


总之,您可以执行以下操作:


@ControllerAdvice

public class MyExceptionHandler extends ResponseEntityExceptionHandler {


    @Override

    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        // ex.getCause().getCause().getClass() gives MyOwnWrittenException

        // the actual logic that handles the exception...

    }

}


查看完整回答
反对 回复 2021-04-21
  • 1 回答
  • 0 关注
  • 221 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信