-
Bug
-
Resolution: Cannot Reproduce
-
Major
-
None
-
3.12.1.Final, 3.14.0.Final, 4.6.0.Final
-
None
-
None
-
-
Undefined
In our application, we are using ConstraintViolationException as a single source of exception to all our business validation.
Our application throw custom ConstraintViolationException using the standard annotations mechanism or programmatically like this:
Set<ConstraintViolation<?>> violations = validate(...); if (!violations.isEmpty()) { throw new ConstraintViolationException("custom message here", violations); }
To return theses exceptions through our REST API (either thrown by the standard annotations or programmatically), we have created a "ConstraintViolationException" "ExceptionMapper" such as:
@Provider public class ConstraintViolationExceptionMapper implements ExceptionMapper<ConstraintViolationException> { @Override public Response toResponse(ConstraintViolationException exception) { VndErrors vndErrors = mapConstraintViolationExceptionToVndErrors(exception); return Response .status(Status.BAD_REQUEST) .type("application/vnd.errors+json") .entity(vndErrors) .build(); } public VndErrors mapConstraintViolationExceptionToVndErrors(ConstraintViolationException exception) { String rootMessage = exception.getMessage(); Set<ConstraintViolation<?>> constraintViolations = exception.getConstraintViolations(); // ... custom mapping }
The issue is that after throwing our custom constraint exception, the actual implementation of "ConstraintViolationException" we receive through the "ExceptionMapper" i.e. RestEasy "ResteasyViolationException", and that actual implementation has lost track of the "custom validation message".
I have looked a bit at the source code to find the issue and issue seem caused by RestEasy relying on the following "ConstraintViolationException" constructor
/**
* Creates a constraint violation report.
*
* @param constraintViolations a {@code Set} of {@link ConstraintViolation}s or null
*/
public ConstraintViolationException(Set<? extends ConstraintViolation<?>> constraintViolations) {
this(
constraintViolations != null ? toString( constraintViolations ) : null,
constraintViolations
);
}
instead of the following "ConstraintViolationException" constructor
/**
* Creates a constraint violation report.
*
* @param message error message
* @param constraintViolations a {@code Set} of {@link ConstraintViolation}s or null
*/
public ConstraintViolationException(String message, Set<? extends ConstraintViolation<?>> constraintViolations) {
super( message );
if ( constraintViolations == null ) {
this.constraintViolations = null;
}
else {
this.constraintViolations = new HashSet<>( constraintViolations );
}
}
I'm not sure how the issue should be addressed but my guess is that both RestEasy "ResteasyViolationException" and "GeneralValidatorImpl" classes need some adaptations to actually keep trace of any custom validation message that has been set previously.
If you think appropriate, and given some further implementation guidance, I can volunteer for a PR to resolve this issue in the 3.12 branch (or the one that will be consumed by Wildfly 22) and master.
Thanks!