在我的一个项目中,我已经将Jersey从2.14
版本升级到了2.23
版本。但我为一个问题挣扎了好几个小时。我的项目为ValidationException
定义了自己的ExceptionMapper
,但不幸的是,Jersey已经为这个异常内置了异常映射器,我无法覆盖它
我已经正确注册(我检查了它)我自己的映射器,如下所示:
@Provider
public class ValidationExceptionMapper implements
ExceptionMapper<ValidationException> {
@Override
public Response toResponse(ValidationException exception) {
return Response.status(Status.BAD_REQUEST).build();
}
}
但它从未被调用过。泽西总是选择org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper
。我还尝试为我的自定义映射程序使用@Priority
注释,但不幸的是Jersey没有考虑到这一点。
那到底发生了什么?它在以前的Jersey版本中运行得非常好,所以它似乎是一个回归错误。
我放弃了。有线索吗?
它实际上是Jersey的一个回归错误,于2015年1月引入。
Bug与Jersey的两个扩展有关:用于Weld和bean验证。因为在没有启动Weld容器的情况下,我的自定义ValidationExceptionMapper
映射器优先于jersey-bean-validation
模块提供的内置映射器,所以我的目标实现了。
我在JERSEY-3153下填写了一份错误报告,后来作为问题#3425。
老实说,我再也不会使用Weld+球衣了。。。我对这种组合太厌倦了。在过去的两年里,我已经遇到了大约10个bug。我真的很累。
不管怎样,我希望它能帮助到别人。
更新:正如@Justin Jose在下面的评论中注意到的那样,还有另一种解决上述错误的方法。我们可以使用HK2绑定来覆盖有问题的内置映射程序:
register(new AbstractBinder() {
@Override
protected void configure() {
bind(my.custom.ValidationExceptionMapper.class).to(ExceptionMapper.class)
.in(Singleton.class);
}
});
Jersey内置的ValidationExceptionMapper是通过ValidationFeature注册的。也许,用你自己的版本取代Jersey的ValidationFeature就可以了。可以按如下方式进行。
首先,禁用自动发现验证功能
property(ServerProperties.BV_FEATURE_DISABLE, true);
下一步是注册泽西岛验证功能的克隆
public static class ValidationFeatureClone implements Feature {
@Override
public boolean configure(FeatureContext context) {
context.register(new ValidationBinder());
context.register(NewValidationExceptionMapper.class);
context.register(ValidationErrorMessageBodyWriter.class);
return true;
}
}
在克隆中,您应该指定新的ExceptionMapper。
最后,注册您的新功能
register(ValidationFeatureClone.class)
更新:
从Jersey 2.20起,默认的ValidationExceptionMapper
可以使用HK2绑定覆盖,如下所示。
register(new AbstractBinder() {
@Override
protected void configure() {
bind(NewValidationExceptionMapper.class).to(ExceptionMapper.class)
.in(Singleton.class).ranked(10);
}
});
我找到了一种方法,让它再次与新的Jersey版本一起使用,我也在您的错误报告下发布了它。
需要使用更改后的代码在本地构建Jersey,特别是jersey-bean-validation
工件。
找到org.glassfish.jersey.server.validation.internal.ValidationBinder
并注释掉configure()
中的以下两行:
bind(ValidationExceptionMapper.class).to(ExceptionMapper.class).in(Singleton.class);
bind(ValidationErrorMessageBodyWriter.class).to(MessageBodyWriter.class).in(Singleton.class);
具有讽刺意味的是,这些行上方的源代码注释说,他们应该允许用户注册自己的提供商。
不幸的是,该错误仍然存在,并引起了头痛。。。在我的案例中,最简单的解决方案是专门为ConstraintViolationException提供自定义ExceptionMapper。
public class CVExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(final Throwable t) {
...
}
}
然后一如既往地将其注册到:context.register(CVExceptionMapper.class);