如何覆盖Jersey 2.23中的内置异常映射程序



在我的一个项目中,我已经将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);

最新更新