Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

In one of my projects I've already upgraded Jersey from version 2.14 to 2.23. But I'm struggling many hours with one problem. My project defines its own ExceptionMapper for a ValidationException, but unfortunately Jersey already has a built-in exception mapper for this exception and I cannot override it.

I have registered correctly (I checked it) my own mapper which is presented below:

@Provider
public class ValidationExceptionMapper implements 
         ExceptionMapper<ValidationException> {

    @Override
    public Response toResponse(ValidationException exception) {
        return Response.status(Status.BAD_REQUEST).build();
    }
}

but it is never being called. Jersey always pick up the org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper. I've also tried to use @Priority annotation for my custom mapper, but unfortunately Jersey doesn't take it into account.

So what is going on? It worked perfectly fine in the previous Jersey version, so it seems to be a regression bug.

I give up. Any clues?

like image 786
G. Demecki Avatar asked Jul 31 '16 08:07

G. Demecki


People also ask

What is an exception Mapper?

ExceptionMappers are custom, application provided, components that can catch thrown application exceptions and write specific HTTP responses. The are classes annotated with @Provider and that implement this interface.


2 Answers

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);
    }
});
like image 70
G. Demecki Avatar answered Oct 18 '22 04:10

G. Demecki


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‌​);
    }
});
like image 5
Justin Jose Avatar answered Oct 18 '22 05:10

Justin Jose