jersey icon indicating copy to clipboard operation
jersey copied to clipboard

Jersey doesn't allow to override a built-in ValidationExceptionMapper

Open glassfishrobot opened this issue 8 years ago • 19 comments

In attachments you can see a project which uses: Jersey, Weld, Jetty and jersey bean validation module.

The problem is, when I've upgraded Jersey from 2.14 to 2.23.1 my custom exception mapper:

@Provider
public class ValidationExceptionMapper implements
        ExceptionMapper<ValidationException> {

    @Override
    public Response toResponse(ValidationException exception) {
        final ResponseEntity resp = ResponseEntity.builder()
.message("Hurray, my custom ValidationExceptionMapper was called!")
.build();

        return Response.status(Status.BAD_REQUEST).entity(resp).build();
    }
}

is no longer called - Jersey uses the built-in exception mapper for this exception: org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper and unfortunately I cannot override it.

The problem is strictly related to the Weld integration. Because without dependency to Weld, my custom exception mapper has a higher priority than the one provided by jersey-bean-validation module.

Environment

Windows 7/ Ubuntu 16.04 Oracle JDK 1.7.0_75 Jetty 9.2.13.v20150730 Any Jersey version above 2.14

Affected Versions

[2.23.1]

glassfishrobot avatar Aug 11 '16 09:08 glassfishrobot

Reported by gdemecki

glassfishrobot avatar Aug 11 '16 09:08 glassfishrobot

gdemecki said: Known workarounds:

  • Downgrade to Jersey 2.14
  • Remove Weld
  • Remove jersey-bean-validation module
  • Use HK2 to override the problematic mapper:``` register(new AbstractBinder() { @Override protected void configure() { bind(my.custom.ValidationExceptionMapper.class).to(ExceptionMapper.class) .in(Singleton.class); } });
    
    

BTW: How can I attach a sample reproducer app? Funny, I don't have permissions ^^

glassfishrobot avatar Aug 11 '16 09:08 glassfishrobot

@pavelbucek said: link to a public github repo is best way how to do that, java.net disabled attachments long time ago..

glassfishrobot avatar Aug 11 '16 10:08 glassfishrobot

gdemecki said: Thanks Pavel, example app is available on the GitHub.

glassfishrobot avatar Aug 11 '16 10:08 glassfishrobot

@mpotociar said: I have tried to run your example, but I can see some WELD scanning-related exceptions when I invoke mvn clean package jetty:run from my command line. Please fix this problem in your reproducer.

glassfishrobot avatar Aug 15 '16 10:08 glassfishrobot

@mpotociar said: This is the error that I see: WELD-ENV-000033: Invalid bean archive scanning result - found multiple results with the same reference

glassfishrobot avatar Aug 15 '16 10:08 glassfishrobot

gdemecki said: Thanks Marek, indeed reproducer isn't perfect - I must admit that I've launched it only via the com.xyz.AppRunner.main() from my IDE. Please use it instead of jetty-maven-plugin, if it isn't a problem.

glassfishrobot avatar Aug 17 '16 09:08 glassfishrobot

heinbloed said: We're trying to migrate from GlassFish 4.1 (Jersey 2.10.4) to Payara 4.1.1.164 (Jersey 2.22.2) and are affected by the same problem.

For some reason I don't know, we hadn't implemented the interface but extended the Jersey implementation: @Provider public class ValidationExceptionHandler extends ValidationExceptionMapper. This is why I also noticed that that class is final now. Changing this to @Provider public class ValidationExceptionHandler implements ExceptionMapper<ValidationException> still works in GF 4.1 but no longer in Payara 4.1.1.164, i.e. toResponse(...) is never called.

Since Payara bundles all of the modules named by gdemecki in his workaround suggestions (and we also use all of them), none of them would be possible for us.

glassfishrobot avatar Feb 10 '17 15:02 glassfishrobot

heinbloed said: For anyone else needing a quick fix for this, I managed to have my class implementing ExceptionMapper<ValidationException> get called again by modifying org.glassfish.jersey.server.validation.internal.ValidationBinder.configure() and commenting out the two lines

bind(ValidationExceptionMapper.class).to(ExceptionMapper.class).in(Singleton.class);

and

bind(ValidationErrorMessageBodyWriter.class).to(MessageBodyWriter.class).in(Singleton.class);

I didn't really analyze the source code for that modification, I just noticed that those two lines were added in one of the versions > 2.14. Maybe this helps someone knowledgable in the code to find a real fix.

glassfishrobot avatar Feb 24 '17 14:02 glassfishrobot

This issue was imported from java.net JIRA JERSEY-3153

glassfishrobot avatar Apr 25 '17 05:04 glassfishrobot

Hey guys. I'm running also into this Problem. Is there any progress so far?

deratzmann avatar Oct 13 '17 12:10 deratzmann

same here. this is annoying.

zak905 avatar Oct 19 '17 15:10 zak905

I created an Exception mapper with same name as the one provided by jersey-beans-validation and gave it priority, maybe it can work without priority

@Priority(1)
public class ValidationExceptionMapper implements javax.ws.rs.ext.ExceptionMapper<ValidationException> { 

it works !

zak905 avatar Oct 19 '17 16:10 zak905

It doesn't work for me...Is somebody at jersey having a look on that bug?

import javax.validation.ValidationException; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; @Priority(value = 1) @Provider public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> { @Override public Response toResponse(ValidationException exception) { return Response.status(Response.Status.BAD_REQUEST).entity("message:" + exception.getMessage()).build(); } }

deratzmann avatar Oct 20 '17 11:10 deratzmann

did you try with type parameter javax.ws.rs.ext.ExceptionMapper<ValidationException> ?

zak905 avatar Oct 20 '17 15:10 zak905

I confirm it works without priority, @Provider is enough, I think the important thing is that the type parameter should be ValidationException

zak905 avatar Oct 23 '17 10:10 zak905

Which server do you use? I am using payara full (jersey is included) profile.

deratzmann avatar Oct 24 '17 06:10 deratzmann

Tomcat, Jersey 2.26.

zak905 avatar Oct 24 '17 07:10 zak905

Hello.

This was finally my fix: ` import java.util.Set; import javax.annotation.Priority; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.ws.rs.Priorities; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider;

@Priority(Priorities.USER) @Provider public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {

@Override
public Response toResponse(ConstraintViolationException exc) {
    StringBuilder message = new StringBuilder();
    Set<ConstraintViolation<?>> violations = exc.getConstraintViolations();
    if (violations != null) {
        violations.forEach((violation) -> {
            message.append(violation.getMessage()).append(".");
        });
    }
    return Response.status(Response.Status.BAD_REQUEST).header("message", message.toString()).build();
}

} ` It seems to be that "ConstraintViolationException" must be inserted in the generic expression.

deratzmann avatar Nov 09 '17 11:11 deratzmann