Validating groups example
This topic has not yet been written. The content below is from the topic description.
Let's have a look at an extended Car with Driver example. First we have the class Person (Example 2.12, “Person”) which has a @NotNull constraint on name. Since no group is specified for this annotation its default group is javax.validation.groups.Default. Note When more than one group is requested, the order in which the groups are evaluated is not deterministic. If no group is specified the default group javax.validation.groups.Default is assumed. Example 2.12. Person public class Person { @NotNull private String name; public Person(String name) { this.name = name; } // getters and setters ... } Next we have the class Driver (Example 2.13, “Driver”) extending Person. Here we are adding the properties age and hasDrivingLicense. In order to drive you must be at least 18 (@Min(18)) and you must have a driving license (@AssertTrue). Both constraints defined on these properties belong to the group DriverChecks. As you can see in Example 2.14, “Group interfaces” the group DriverChecks is just a simple tagging interface. Using interfaces makes the usage of groups type safe and allows for easy refactoring. It also means that groups can inherit from each other via class inheritance. Note The Bean Validation specification does not enforce that groups have to be interfaces. Non interface classes could be used as well, but we recommend to stick to interfaces. Example 2.13. Driver public class Driver extends Person { @Min(value = 18, message = "You have to be 18 to drive a car", groups = DriverChecks.class) public int age; @AssertTrue(message = "You first have to pass the driving test", groups = DriverChecks.class) public boolean hasDrivingLicense; public Driver(String name) { super( name ); } public void passedDrivingTest(boolean b) { hasDrivingLicense = b; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } Example 2.14. Group interfaces public interface DriverChecks { } public interface CarChecks { } Last but not least we add the property passedVehicleInspection to the Car class (Example 2.15, “Car”) indicating whether a car passed the road worthy tests. Example 2.15. Car public class Car { @NotNull private String manufacturer; @NotNull @Size(min = 2, max = 14) private String licensePlate; @Min(2) private int seatCount; @AssertTrue(message = "The car has to pass the vehicle inspection first", groups = CarChecks.class) private boolean passedVehicleInspection; @Valid private Driver driver; public Car(String manufacturer, String licencePlate, int seatCount) { this.manufacturer = manufacturer; this.licensePlate = licencePlate; this.seatCount = seatCount; } } Overall three different groups are used in our example. Person.name, Car.manufacturer, Car.licensePlate and Car.seatCount all belong to the Default group. Driver.age and Driver.hasDrivingLicense belong to DriverChecks and last but not least Car.passedVehicleInspection belongs to the group CarChecks. Example 2.16, “Drive away” shows how passing different group combinations to the Validator.validate method result in different validation results. Example 2.16. Drive away public class GroupTest { private static Validator validator; @BeforeClass public static void setUp() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } @Test public void driveAway() { // create a car and check that everything is ok with it. Car car = new Car( "Morris", "DD-AB-123", 2 ); Set > constraintViolations = validator.validate( car ); assertEquals( 0, constraintViolations.size() ); // but has it passed the vehicle inspection? constraintViolations = validator.validate( car, CarChecks.class ); assertEquals( 1, constraintViolations.size() ); assertEquals("The car has to pass the vehicle inspection first", constraintViolations.iterator().next().getMessage()); // let's go to the vehicle inspection car.setPassedVehicleInspection( true ); assertEquals( 0, validator.validate( car ).size() ); // now let's add a driver. He is 18, but has not passed the driving test yet Driver john = new Driver( "John Doe" ); john.setAge( 18 ); car.setDriver( john ); constraintViolations = validator.validate( car, DriverChecks.class ); assertEquals( 1, constraintViolations.size() ); assertEquals( "You first have to pass the driving test", constraintViolations.iterator().next().getMessage() ); // ok, John passes the test john.passedDrivingTest( true ); assertEquals( 0, validator.validate( car, DriverChecks.class ).size() ); // just checking that everything is in order now assertEquals( 0, validator.validate( car, Default.class, CarChecks.class, DriverChecks.class ).size() ); } } First we create a car and validate it using no explicit group. There are no validation errors, even though the property passedVehicleInspection is per default false. However, the constraint defined on this property does not belong to the default group. Next we just validate the CarChecks group which will fail until we make sure that the car passes the vehicle inspection. When we then add a driver to the car and validate against DriverChecks we get again a constraint violation due to the fact that the driver has not yet passed the driving test. Only after setting passedDrivingTest to true the validation against DriverChecks will pass. Last but not least, we show that all constraints are passing by validating against all defined groups.