[[chapter-groups]]
== Grouping constraints

All validation methods on `Validator` and `ExecutableValidator` discussed in earlier chapters also take
a var-arg argument `groups`. So far we have been ignoring this parameter, but it is time to have a
closer look.

=== Requesting groups

Groups allow you to restrict the set of constraints applied during validation. One use case for
validation groups are UI wizards where in each step only a specified subset of constraints should
get validated. The groups targeted are passed as var-arg parameters to the appropriate validate
method.

Let's have a look at an example. The class `Person` in <<example-person>> has a `@NotNull`
constraint on `name`. Since no group is specified for this annotation the default group
`javax.validation.groups.Default` is assumed.

[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-person]]
.Example class `Person`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/Person.java[tags=include]
----
====

The class `Driver` in <<example-driver>> extends `Person` and adds the properties `age` and
`hasDrivingLicense`. Drivers must be at least 18 years old (`@Min(18)`) and have a driving license
(`@AssertTrue`). Both constraints defined on these properties belong to the group `DriverChecks` which
is just a simple tagging interface.

[TIP]
====
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. See <<section-group-inheritance>>.
====

[[example-driver]]
.Driver
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/Driver.java[tags=include]
----

[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/DriverChecks.java[]
----
====

Finally the class `Car` (<<example-car>>) has some constraints which are part of the default group as
well as `@AssertTrue` in the group `CarChecks` on the property `passedVehicleInspection` which indicates
whether a car passed the road worthy tests.

[[example-car]]
.Car
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/Car.java[tags=include]
----

[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/CarChecks.java[]
----
====

Overall three different groups are used in the example:

* The constraints on `Person.name`, `Car.manufacturer`, `Car.licensePlate` and `Car.seatCount`
all belong to the `Default` group
* The constraints on `Driver.age` and `Driver.hasDrivingLicense` belong to `DriverChecks`
* The constraint on `Car.passedVehicleInspection` belongs to the group `CarChecks`

<<example-drive-away>> shows how passing different group combinations to the `Validator#validate()`
method results in different validation results.

[[example-drive-away]]
.Using validation groups
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/GroupTest.java[tags=driveAway]
----
====

The first `validate()` call in <<example-drive-away>> is done using no explicit group. There are no
validation errors, even though the property `passedVehicleInspection` is per default `false` as
the constraint defined on this property does not belong to the default group.

The next validation using the `CarChecks` group fails until the car passes the vehicle inspection.
Adding a driver to the car and validating against `DriverChecks` again yields one 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` passes.

The last `validate()` call finally shows that all constraints are passing by validating against all
defined groups.

[[section-group-inheritance]]
=== Group inheritance

In <<example-drive-away>>, we need to call `validate()` for each validation group, or specify all of
them one by one.

In some situations, you may want to define a group of constraints which includes another group.
You can do that using group inheritance.

In <<example-supercar>>, we define a `SuperCar` and a group `RaceCarChecks` that extends the `Default` group.
A `SuperCar` must have safety belts to be allowed to run in races.

[[example-supercar]]
.SuperCar
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/groupinheritance/SuperCar.java[tags=include]
----

[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/groupinheritance/RaceCarChecks.java[]
----
====

In the example below, we will check if a `SuperCar` with one seat and no security belts is a valid car
and if it is a valid race-car.

[[example-group-inheritance]]
.Using group inheritance
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/GroupTest.java[tags=testGroupInheritance]
----
====

On the first call to `validate()`, we do not specify a group. There is one validation error because a
car must have at least one seat. It is the constraint from the `Default` group.

On the second call, we specify only the group `RaceCarChecks`. There are two validation errors: one
about the missing seat from the `Default` group, another one about the fact that there is no safety
belts coming from the `RaceCarChecks` group.

[[section-defining-group-sequences]]
=== Defining group sequences

By default, constraints are evaluated in no particular order, regardless of which groups they belong
to. In some situations, however, it is useful to control the order in which constraints are evaluated.

In the example from <<example-drive-away>> it could for instance be required that first all default
car constraints are passing before checking the road worthiness of the car. Finally, before driving
away, the actual driver constraints should be checked.

In order to implement such a validation order you just need to define an interface and annotate it
with `@GroupSequence`, defining the order in which the groups have to be validated (see
<<example-defining-group-sequence>>). If at least one constraint fails in a sequenced group, none of the
constraints of the following groups in the sequence get validated.

[[example-defining-group-sequence]]
.Defining a group sequence
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/OrderedChecks.java[]
----
====

[WARNING]
====
Groups defining a sequence and groups composing a sequence must not be involved in a cyclic
dependency either directly or indirectly, either through cascaded sequence definition or group
inheritance. If a group containing such a circularity is evaluated, a `GroupDefinitionException` is
raised.
====

You then can use the new sequence as shown in in <<example-group-sequence>>.

[[example-group-sequence]]
.Using a group sequence
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/GroupTest.java[tags=testOrderedChecks]
----
====

[[section-default-group-class]]
=== Redefining the default group sequence

==== `@GroupSequence`

Besides defining group sequences, the `@GroupSequence` annotation also allows to redefine the default
group for a given class. To do so, just add the `@GroupSequence` annotation to the class and specify
the sequence of groups which substitute `Default` for this class within the annotation.

<<example-rental-car>> introduces a new class `RentalCar` with a redefined default group.

[[example-rental-car]]
.Class `RentalCar` with redefined default group
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/RentalCar.java[tags=include]
----

[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/RentalChecks.java[]
----
====

With this definition you can evaluate the constraints belonging to `RentalChecks`, `CarChecks` and
`RentalCar` by just requesting the `Default` group as seen in <<example-testCarIsRented>>.

[[example-testCarIsRented]]
.Validating an object with redefined default group
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/GroupTest.java[tags=carIsRented]
----
====

[NOTE]
====
Since there must be no cyclic dependency in the group and group sequence definitions, one cannot just
add `Default` to the sequence redefining `Default` for a class. Instead the class itself has to be
added.
====

The `Default` group sequence overriding is local to the class it is defined on and is not propagated
to associated objects. For the example, this means that adding `DriverChecks` to the default group
sequence of `RentalCar` would not have any effects. Only the group `Default` will be propagated to the
driver association.

Note that you can control the propagated group(s) by declaring a group conversion rule (see
<<section-group-conversion>>).

==== `@GroupSequenceProvider`

In addition to statically redefining default group sequences via `@GroupSequence`, Hibernate Validator
also provides an SPI for the dynamic redefinition of default group sequences depending on the object
state.

For that purpose, you need to implement the interface `DefaultGroupSequenceProvider` and register this
implementation with the target class via the `@GroupSequenceProvider` annotation. In the rental car
scenario, you could for instance dynamically add the `CarChecks` as seen in
<<example-implementing-using-default-group-sequence-provider>>.

[[example-implementing-using-default-group-sequence-provider]]
.Implementing and using a default group sequence provider
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/groupsequenceprovider/RentalCarGroupSequenceProvider.java[tags=include]
----

[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/groupsequenceprovider/RentalCar.java[tags=include]
----
====

[[section-group-conversion]]
=== Group conversion

What if you wanted to validate the car related checks together with the driver checks? Of course you
could pass the required groups to the validate call explicitly, but what if you wanted to make these
validations occur as part of the `Default` group validation? Here `@ConvertGroup` comes into play which
allows you to use a different group than the originally requested one during cascaded validation.

Let's have a look at <<example-group-conversion-dedault-to-driver-checks>>. Here `@GroupSequence({
CarChecks.class, Car.class })` is used to combine the car related constraints under the `Default` group
(see <<section-default-group-class>>). There is also a `@ConvertGroup(from = Default.class, to =
DriverChecks.class)` which ensures the `Default` group gets converted to the `DriverChecks` group during
cascaded validation of the driver association.

[[example-group-conversion-dedault-to-driver-checks]]
.`@ConvertGroup` usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/groupconversion/Driver.java[tags=include]
----

[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/groupconversion/Car.java[tags=include]
----
====

As a result the validation in <<example-group-conversion-test>> succeeds, even though the constraint
on `hasDrivingLicense` belongs to the `DriverChecks` group and only the `Default` group is requested in
the `validate()` call.

[[example-group-conversion-test]]
.Test case for `@ConvertGroup`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter05/groupconversion/GroupConversionTest.java[tags=validateDriverChecksTogetherWithCarChecks]
----
====

You can define group conversions wherever `@Valid` can be used, namely associations as well as method
and constructor parameters and return values. Multiple conversions can be specified using
`@ConvertGroup.List`.

However, the following restrictions apply:

* `@ConvertGroup` must only be used in combination with `@Valid`. If used without, a
`ConstraintDeclarationException` is thrown.

* It is not legal to have multiple conversion rules on the same element with the same from value.
In this case, a `ConstraintDeclarationException` is raised.

* The `from` attribute must not refer to a group sequence. A `ConstraintDeclarationException` is
raised in this situation.

[NOTE]
====
Rules are not executed recursively. The first matching conversion rule is used and subsequent rules
are ignored. For example if a set of `@ConvertGroup` declarations chains group `A` to `B` and
`B` to `C`, the group `A` will be converted to `B` and not to `C`.
====
