What's the best way to invoke class level JSR-303 constraints that do cross field validation from JSF and have the resulting messages get translated to a FacesMessage and be tied to a particular JSF component based on the PropertyPath in the ConstraintViolation?
rich:graphValidator is close, but it doesn't make use of the PropertyPath. Perhaps MyFaces extval could get me close, but there seems to be a whole extra layer of framework on time of bean-validation, so I avoided it.
Here's a simple example:
public enum Type {
ROAD, RACE;
}
public class Driver {
private String name;
private Type licenseType;
...
}
@CarConstraint
public class Car {
@Valid
private Driver driver;
private Type carType;
private String make;
private String model;
...
}
public class CarConstraintValidator implements ConstraintValidator<CarConstraint, Car> {
@Override
public void initialize(CarConstraint constraintAnnotation) {}
@Override
public boolean isValid(Car value, ConstraintValidatorContext context) {
if (value == null) { return true; }
if (Type.RACE.equals(value.getCarType())
&& !Type.RACE.equals(value.getDriver().getLicenseType())) {
context.buildConstraintViolationWithTemplate("Driver of this car must have a racing license")
.addNode("driver")
.addNode("licenseType")
.addConstraintViolation();
return false;
}
return true;
}
}
Picture a form where the information about the car and the driver are input. If the Driver had a license type of ROAD and the Car had a car type of RACE, it'd be ideal to see a resulting validation message be translated into a FacesMessage which is connected to the input for license type, since the message was added to that node using the fluent API of Bean Validation.