You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何处理MicroProfile REST服务输入枚举字段的校验错误

问题根因

枚举值不匹配的错误发生在JSON反序列化阶段,该阶段早于接口方法调用、参数校验阶段,因此请求不会进入你实现的RetrieveService业务方法,默认会直接返回400错误。

MicroProfile完全兼容JAX-RS规范,你可以通过以下两种方案实现自定义错误返回:

方案1:全局异常拦截(推荐)

通过JAX-RS的ExceptionMapper全局拦截反序列化阶段的枚举格式错误,无需修改业务代码。
根据你项目使用的JSON处理工具选择对应实现:

若使用Jackson(MicroProfile默认常用实现)

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Provider
public class EnumFormatExceptionMapper implements ExceptionMapper<InvalidFormatException> {
    @Override
    public Response toResponse(InvalidFormatException e) {
        // 判断是否为枚举类型反序列化错误
        if (e.getTargetType().isEnum()) {
            String allowedValues = Stream.of(e.getTargetType().getEnumConstants())
                    .map(Object::toString)
                    .collect(Collectors.joining("、"));
            String errorMsg = String.format("非法参数值 '%s',%s字段允许的值为:%s",
                    e.getValue(), e.getPath().get(0).getFieldName(), allowedValues);
            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Collections.singletonMap("error", errorMsg))
                    .build();
        }
        // 其他格式错误自定义返回
        return Response.status(Response.Status.BAD_REQUEST)
                .entity(Collections.singletonMap("error", "请求参数格式错误"))
                .build();
    }
}

若使用JSON-B

import javax.json.bind.JsonbException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Provider
public class JsonbEnumExceptionMapper implements ExceptionMapper<JsonbException> {
    private static final Pattern ENUM_ERROR_PATTERN = Pattern.compile("No enum constant (\\w+)\\.(\\w+)\\.(\\w+)");

    @Override
    public Response toResponse(JsonbException e) {
        Matcher matcher = ENUM_ERROR_PATTERN.matcher(e.getMessage());
        if (matcher.find()) {
            String errorMsg = String.format("非法的%s参数值,允许的值为:LONDON、LIVERPOOL", matcher.group(3));
            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Collections.singletonMap("error", errorMsg))
                    .build();
        }
        return Response.status(Response.Status.BAD_REQUEST)
                .entity(Collections.singletonMap("error", "请求参数格式错误"))
                .build();
    }
}

加了@Provider注解的异常处理器会被MicroProfile运行时自动扫描生效,无需额外配置。

方案2:业务层校验(符合你想在RetrieveService里处理的需求)

把User类的枚举字段改为String类型,避免反序列化阶段报错,再在业务方法里手动做枚举转换校验:

  1. 修改User类定义
public class User {
  String name;
  String surname;
  String city; // 从CityEnum改为String类型

  // getter和setter保持@NotNull注解不变
}
  1. 在RetrieveService里做校验
@Service
public class RetrieveService implements Retrieve {
    @Override
    public Response retrieveValue(@Valid User user) {
        CityEnum cityEnum;
        try {
            // 手动转换为枚举
            cityEnum = CityEnum.valueOf(user.getCity().toUpperCase());
        } catch (IllegalArgumentException e) {
            // 自定义错误返回
            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Collections.singletonMap("error", "城市参数非法,允许的值为:LONDON、LIVERPOOL"))
                    .build();
        }
        // 后续正常业务逻辑
        return Response.ok().build();
    }
}

内容的提问来源于stack exchange,提问作者Prodox21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 04:18:00