如何检查枚举中不存在的值并抛出自定义异常,优化JSON解析错误提示信息
好的,我来帮你搞定这个枚举参数校验的问题——那种默认的JSON解析错误确实太冗长了,用户完全get不到哪里错了。下面分几种场景给你实用的解决方案,不管你是Spring Boot项目还是普通Java工程都能用上:
如果你是用Spring Boot做接口,直接全局捕获枚举转换时的异常,然后返回清晰的自定义提示就行。默认情况下,当传入非法枚举值时,Jackson会抛出JsonMappingException或者IllegalArgumentException,我们可以写一个全局异常处理器来拦截:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler({JsonMappingException.class, IllegalArgumentException.class}) public ResponseEntity<Map<String, String>> handleEnumInvalidException(Exception e) { // 提取错误信息里的非法值,或者直接给出通用提示 String errorMsg = "无效的枚举参数值,请传入AC或CD"; // 如果你想更精准,可以从异常信息里解析出用户传的无效值: // String invalidValue = extractInvalidValueFromException(e); // errorMsg = String.format("无效的枚举参数值:%s,请传入AC或CD", invalidValue); Map<String, String> response = new HashMap<>(); response.put("code", "400"); response.put("message", errorMsg); return ResponseEntity.badRequest().body(response); } // 可选:解析异常信息里的无效值,比如Jackson的错误信息会包含"DF" private String extractInvalidValueFromException(Exception e) { String message = e.getMessage(); // 简单匹配,实际可以根据异常类型调整正则 Pattern pattern = Pattern.compile("\\[([A-Za-z0-9]+)\\]"); Matcher matcher = pattern.matcher(message); if (matcher.find()) { return matcher.group(1); } return "未知"; } }
这样用户传"DF"的时候,就会收到清晰的{"code":"400","message":"无效的枚举参数值:DF,请传入AC或CD"},而不是一堆晦涩的堆栈信息。
如果想在JSON解析阶段就主动校验枚举值,而不是等异常抛出,我们可以给枚举写一个自定义的Jackson反序列化器:
首先定义枚举:
public enum Metadata { AC, CD; // 自定义方法:判断值是否属于枚举 public static boolean isValid(String value) { if (value == null) return false; for (Metadata meta : values()) { if (meta.name().equals(value)) { return true; } } return false; } }
然后写自定义反序列化器:
public class MetadataDeserializer extends StdDeserializer<Metadata> { public MetadataDeserializer() { super(Metadata.class); } @Override public Metadata deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String value = p.getText().trim(); if (!Metadata.isValid(value)) { // 抛出自定义异常,或者直接返回null(不推荐,还是抛异常更清晰) throw new IllegalArgumentException(String.format("无效的Metadata值:%s,可选值为AC、CD", value)); } return Metadata.valueOf(value); } }
最后给枚举加上注解,指定反序列化器:
@JsonDeserialize(using = MetadataDeserializer.class) public enum Metadata { AC, CD; // 上面的isValid方法保留 }
这样当传入非法值时,会直接抛出我们自定义的异常,再配合上面的全局异常处理器,就能返回完美的提示了。
如果你的项目不是Spring Boot,或者只是在某个方法里手动处理参数,那可以直接用try-catch或者自定义工具类来校验:
// 方法1:用try-catch捕获Enum.valueOf的异常 public void processMetadata(String metadataStr) { Metadata metadata; try { metadata = Metadata.valueOf(metadataStr); } catch (IllegalArgumentException e) { throw new CustomException("无效的枚举值,请传入AC或CD"); // 自定义异常类 // 或者直接返回错误提示: // return ResponseEntity.badRequest().body("无效的枚举值,请传入AC或CD"); } // 业务逻辑... } // 方法2:用自定义的isValid方法提前判断 public void processMetadata(String metadataStr) { if (!Metadata.isValid(metadataStr)) { throw new CustomException("无效的枚举值,请传入AC或CD"); } Metadata metadata = Metadata.valueOf(metadataStr); // 业务逻辑... }
这里的CustomException是你自己定义的异常类,比如:
public class CustomException extends RuntimeException { public CustomException(String message) { super(message); } }
这样就能在参数进入业务逻辑前就拦截非法值,给出清晰提示。
总结一下:如果是Web项目,优先用全局异常处理器+自定义反序列化器的组合,既提前校验又统一返回格式;如果是普通Java项目,手动校验或者自定义反序列化器都可以。
内容的提问来源于stack exchange,提问作者danceAyush

