![](/img/trans.png)
[英]ControllerAdvice cannot catch custom exception in Spring Boot
[英]Catch a deserialization exception before a ControllerAdvice
這是一個問題:我有一個采用輸入模型的控制器。 可以說
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
有一些阻止無效日期字符串的驗證。 我的異常有一個處理程序:
@ControllerAdvice
public 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(
UPD感謝@Joe Doe 的回答問題已經解決。 這是我更新的處理程序:
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public 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);
}
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
Throwable cause = ex.getCause();
String message = null;
if (cause instanceof JsonMappingException) {
if (cause.getCause() instanceof MyOwnWrittenException) {
return handleInvalidRequest((RuntimeException) cause.getCause(), request);
} else {
message = cause.getMessage();
}
} else {
message = ex.getMessage();
}
AbstractUnsuccessfulResult result = new AbstractUnsuccessfulResult(
new BasicErrorMessage(message));
headers.setContentType(MediaType.APPLICATION_JSON);
return handleExceptionInternal(ex, result, headers, HttpStatus.BAD_REQUEST, request);
}
}
UPD在我的項目中,如果沒有注釋@Order(Ordered.HIGHEST_PRECEDENCE)
我相信這是因為項目中的 ControllerAdvices 數量
在調用控制器中的updateUser
之前,必須解析其參數。 這是HandlerMethodArgumentResolverComposite
用武之地,並委托給預注冊的HandlerMethodArgumentResolver
- 在這種特殊情況下,它委托給RequestResponseBodyMethodProcessor
。
通過委托,我的意思是調用解析器的resolveArgument
方法。 這種方法間接地調用deserialize
從解串器,其拋出類型的異常方法MyOwnWrittenException
。 問題是這個異常被另一個異常包裹了。 事實上,當它傳播回resolveArgument
,它的類型是HttpMessageNotReadableException
。
因此, MyOwnWrittenException
在自定義異常處理程序中捕獲MyOwnWrittenException
,不如捕獲MyOwnWrittenException
類型的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...
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.