在将HTTP请求数据转换为枚举时捕获异常

时间:2018-06-07 07:57:03

标签: java spring-boot jackson json-deserialization

使用自定义com.fasterxml.jackson.databind.JsonDeserializer反序列化器实现将HTTP请求值反序列化为枚举时遇到问题:

public class EnvelopeColorJsonDeserializer extends JsonDeserializer<EnvelopeColor> {

    @Override
    public EnvelopeColor deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String val = p.getValueAsString();
        return EnvelopeColor.fromCode(val);
    }
}

这是我将值转换为枚举的方式:

public static EnvelopeColor fromCode(String code) {
    Assert.notNull(code, "code");
    for (EnvelopeColor type : values()) {
        if (code.equals(type.code)) {
            return type;
        }
    }
    throw new RuntimeException("Not supported color: " + code);
}

端点:

@PostMapping("/")
    public @ResponseBody
    ResponseEntity add(@RequestBody EnvelopeDto envelope) {
// some stuff goes here...
}

问题

有没有办法如何a)检查HTTP请求值是否有效枚举常量值进行反序列化过程之前或b)如何在@ControllerAdvice异常处理程序中捕获异常? (我想避免在fromCode()方法中抛出自定义异常。)

2 个答案:

答案 0 :(得分:1)

您可以为类HttpMessageNotReadableException添加异常处理程序。 当Spring无法将有效负载反序列化为DTO时,抛出此异常。

@ExceptionHandler(org.springframework.http.converter.HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
protected @ResponseBody handleIncorrectData(HttpMessageNotReadableException ex,
            HttpServletRequest request, HttpServletResponse response){

....

}

此外,您可以定义一个自定义EnumConverter,它会向用户提供正确的枚举值。

public class CustomEnumConverter extends EnumConverter {

    @Override
    public Object unmarshal(HierarchicalStreamReader reader,
            UnmarshallingContext context) {
        try {
            return super.unmarshal(reader, context);
        } catch (IllegalArgumentException e) {
            String inputValue = reader.getValue();
            Class contextType = context.getRequiredType();
            StringBuilder sb = new StringBuilder();
            Object[] enumConstants = contextType.getEnumConstants();
            for (Object o : enumConstants) {
                sb.append(o + ",");
            }
            if (sb.length() > 0)
                sb.deleteCharAt(sb.length() - 1);
            throw new InvalidArgumentException(ErrorCode.INVALID_ARGUMENT, inputValue,
                    reader.getNodeName(), sb.toString());
        }
    }

}

答案 1 :(得分:-1)

对于@ControllerAdvice异常处理程序中的catch异常,请尝试:

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ApplicationExceptionHandler {

    private static Logger logger = LoggerFactory.getLogger(ApplicationExceptionHandler.class);

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({RuntimeException.class})
    public @ResponseBody Response<Error> handleIllegalArgumentException(Exception e) {
        logger.error("BadRequestException :: ", e);
        return new Response<Error>(new Error("BadRequestException", e.getMessage()));
    }

}