How to override a built-in exception mapper in Jersey 2.23?

Jersey's built-in ValidationExceptionMapper is registered via ValidationFeature. Probably, replacing Jersey's ValidationFeature with your own version can do the trick. It can be done as follows.

Firstly, disable auto-discoverable ValidationFeature

property(ServerProperties.BV_FEATURE_DISABLE, true);

Next step is to register a clone of Jersey's validation feature

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;
    }
}

In the clone, you should specify your new ExceptionMapper.

Finally, register your new Feature

register(ValidationFeatureClone.class)

UPDATE:

From Jersey 2.20 onwards, default ValidationExceptionMapper can be overwritten using HK2 binding as shown below.

register(new AbstractBinder() {
    @Override
    protected void configure() {

       bind(NewValidationExceptionMapper.class).to(ExceptionMapper.class)
           .in(Singleton.class).ranked(10‌​);
    }
});

It really turned out to be a regression bug in Jersey, introduced in January 2015.

Bug is related with two Jersey's extensions: for Weld and bean validation. Because without Weld container started, my custom ValidationExceptionMapper mapper takes precedence over the built-in one provided by the jersey-bean-validation module, so my goal is achieved.

I've filled a bug report under JERSEY-3153, later moved as the issue #3425.

To be honest, I'm never ever going to use Weld + Jersey again... I'm so tired with this combination. Through the last two years I've encountered around 10 bugs already. I'm really tired.

Anyway, I hope it will help somebody.

UPDATE: As @Justin Jose noticed in the comments below, there is also another workaround for the mentioned bug. We can use HK2 bindings, to override the problematic built-in mapper:

register(new AbstractBinder() {
    @Override
    protected void configure() {
        bind(my.custom.ValidationExceptionMapper.class).to(ExceptionMapper.class)
               .in(Singleton.class);
    }
});