Jersey 2.25.1:如何禁用默认ExceptionMapper或提升自定义Mapper优先级
问题背景
使用Jersey 2.25.1开发RESTful API,要求所有错误场景下返回统一格式的JSON。为此自定义了JsonParseExceptionMapper处理JSON解析异常,但发现Jersey会自动注册默认的com.fasterxml.jackson.jaxrs.base.JsonParseExceptionMapper,且两者的注册顺序随机:自定义Mapper优先时返回application/json(符合预期),默认Mapper优先时返回text/plain(导致测试失败)。
原因分析
默认的JsonParseExceptionMapper通过jersey-media-json-jackson依赖引入,Jersey的JacksonFeature会自动注册Jackson提供的这类异常Mapper——即使Jackson 2.8+移除了它们的@Provider注解,Jersey仍会通过模块扫描完成注册。
解决方案
方案一:禁用默认的Jackson异常Mapper
通过Jersey配置属性,阻止自动注册Jackson自带的ExceptionMapper:
@Override protected Application configure() { ResourceConfig config = new ResourceConfig(); config.register(HelloResource.class); config.register(StartupProvidersLogger.class); config.register(JsonParseExceptionMapper.class); // 禁用Jackson默认的ExceptionMapper注册 config.property(org.glassfish.jersey.jackson.JacksonProperties.PROP_FEATURE_DISABLE_MAPPER_PROVIDERS, true); return config; }
该配置会直接屏蔽Jackson自带的JsonParseExceptionMapper和JsonMappingExceptionMapper,确保仅自定义Mapper生效。
方案二:提升自定义Mapper的优先级
使用Jersey的@Priority注解为自定义Mapper设置更高优先级(数值越小优先级越高,默认ExceptionMapper优先级为5000):
@Provider @Priority(javax.ws.rs.Priorities.USER) // USER优先级为1000,高于默认的5000 public static class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> { protected static final Logger logger = LogManager.getLogger(AbstractExceptionMapper.class); @Override public Response toResponse(JsonParseException exception) { return Response.status(Response.Status.BAD_REQUEST) .entity("{\"result\": false}") .type(MediaType.APPLICATION_JSON) .build(); } }
此方式下,无论注册顺序如何,Jersey都会优先调用优先级更高的自定义Mapper处理异常。
验证效果
修改后重新运行测试,无论注册顺序如何,响应媒体类型都会稳定为application/json,符合统一错误格式要求。
内容的提问来源于stack exchange,提问作者Charles

