Jackson未抛出自定义异常求助:日期反序列化异常未被正确捕获
问题:自定义LocalDate反序列化异常未被全局处理器捕获,返回通用400错误
相关代码
实体类字段定义
@NotNull @JsonDeserialize(using = LocalDateDeserializer.class) @Schema(description = "BIRTH DATE", example = "1992-02-15") private LocalDate birthDate;
自定义Jackson反序列化器
public class LocalDateDeserializer extends StdDeserializer<LocalDate> { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); protected LocalDateDeserializer() { super(LocalDate.class); } @Override public LocalDate deserialize( final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException { JsonNode node = jsonParser.getCodec().readTree(jsonParser); String date = node.asText(); try { return LocalDate.parse(date, DATE_TIME_FORMATTER); } catch (Exception e) { throw new InvalidDateFormatException("Invalid format" + date); } } }
自定义异常类
public class InvalidDateFormatException extends RuntimeException { public InvalidDateFormatException(final String message) { super(message); } }
全局异常处理器
@ControllerAdvice public class ApplicationExceptionHandler extends ResponseEntityExceptionHandler { public static final String MISSING_HEADER_MESSAGE = "{0} header must be informed"; @ExceptionHandler(InvalidDateFormatException.class) public ResponseEntity<String> handleInvalidDateFormatException(InvalidDateFormatException ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); } }
问题现象
发送格式错误的birthDate请求时,代码进入反序列化器并捕获到异常,但自定义错误未生效,仅返回通用400错误。
解决方案
核心原因:Jackson反序列化阶段抛出的自定义异常会被Spring的HttpMessageConverter包装成HttpMessageNotReadableException,而继承ResponseEntityExceptionHandler的全局处理器默认会处理这个包装后的异常,导致自定义异常的处理器无法触发。
方式一:修改反序列化器,使用Jackson内置异常处理机制
调整反序列化器的异常抛出逻辑,利用Jackson的DeserializationContext抛出规范异常,让Spring能正确识别错误信息:
@Override public LocalDate deserialize( final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException { JsonNode node = jsonParser.getCodec().readTree(jsonParser); String date = node.asText(); try { return LocalDate.parse(date, DATE_TIME_FORMATTER); } catch (Exception e) { // 用Jackson的方法抛出格式错误异常 return deserializationContext.handleWeirdStringValue(LocalDate.class, date, "Invalid format: " + date); } }
然后在全局处理器中重写handleHttpMessageNotReadable方法,返回自定义响应:
@Override protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { Throwable cause = ex.getCause(); if (cause instanceof JsonMappingException) { // 提取Jackson抛出的错误信息返回 return new ResponseEntity<>(cause.getMessage(), HttpStatus.BAD_REQUEST); } // 其他情况沿用默认处理 return super.handleHttpMessageNotReadable(ex, headers, status, request); }
方式二:在全局处理器中处理包装后的异常
无需修改反序列化器,直接在全局处理器中新增对HttpMessageNotReadableException的处理,提取根异常判断是否为自定义异常:
@ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity<String> handleHttpMessageNotReadable(HttpMessageNotReadableException ex) { Throwable rootCause = ex.getRootCause(); if (rootCause instanceof InvalidDateFormatException) { return new ResponseEntity<>(rootCause.getMessage(), HttpStatus.BAD_REQUEST); } return new ResponseEntity<>("Invalid request body", HttpStatus.BAD_REQUEST); }
内容的提问来源于stack exchange,提问作者Jossany Moura
相关产品推荐
相关产品推荐

