jersey
jersey copied to clipboard
Jersey doesn't allow to override a built-in ValidationExceptionMapper
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]
Reported by gdemecki
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 ^^
@pavelbucek said: link to a public github repo is best way how to do that, java.net disabled attachments long time ago..
gdemecki said: Thanks Pavel, example app is available on the GitHub.
@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.
@mpotociar said: This is the error that I see: WELD-ENV-000033: Invalid bean archive scanning result - found multiple results with the same reference
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.
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.
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.
This issue was imported from java.net JIRA JERSEY-3153
Hey guys. I'm running also into this Problem. Is there any progress so far?
same here. this is annoying.
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 !
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(); } }
did you try with type parameter javax.ws.rs.ext.ExceptionMapper<ValidationException>
?
I confirm it works without priority, @Provider
is enough, I think the important thing is that the type parameter should be ValidationException
Which server do you use? I am using payara full (jersey is included) profile.
Tomcat, Jersey 2.26.
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.