[[chapter-method-constraints]]
== Declaring and validating method constraints

As of Bean Validation 1.1, constraints can not only be applied to JavaBeans and their properties,
but also to the parameters and return values of the methods and constructors of any Java type. That
way Jakarta Validation constraints can be used to specify

* the preconditions that must be satisfied by the caller before a method or constructor may be
invoked (by applying constraints to the parameters of an executable)
* the postconditions that are guaranteed to the caller after a method or constructor invocation
returns (by applying constraints to the return value of an executable)

[NOTE]
====
For the purpose of this reference guide, the term _method constraint_ refers to both, method and
constructor constraints, if not stated otherwise. Occasionally, the term _executable_ is used when
referring to methods and constructors.
====

This approach has several advantages over traditional ways of checking the correctness of parameters
and return values:

* the checks don't have to be performed manually (e.g. by throwing `IllegalArgumentException` or
similar), resulting in less code to write and maintain
* an executable's pre- and postconditions don't have to be expressed again in its documentation,
since the constraint annotations will automatically be included in the generated JavaDoc. This
avoids redundancies and reduces the chance of inconsistencies between implementation and
documentation

[TIP]
====
In order to make annotations show up in the JavaDoc of annotated elements, the annotation types
themselves must be annotated with the meta annotation @Documented. This is the case for all built-in
constraints and is considered a best practice for any custom constraints.
====

In the remainder of this chapter you will learn how to declare parameter and return value
constraints and how to validate them using the `ExecutableValidator` API.

[[section-declaring-method-constraints]]
=== Declaring method constraints

==== Parameter constraints

You specify the preconditions of a method or constructor by adding constraint annotations to its
parameters as demonstrated in <<example-declaring-parameter-constraints>>.

[[example-declaring-parameter-constraints]]
.Declaring method and constructor parameter constraints
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/parameter/RentalStation.java[tags=include]
----
====

The following preconditions are declared here:

* The `name` passed to the `RentalStation` constructor must not be `null`
* When invoking the `rentCar()` method, the given `customer` must not be `null`, the rental's start
date must not be `null` as well as be in the future and finally the rental duration must be at least
one day

Note that declaring method or constructor constraints itself does not automatically cause their
validation upon invocation of the executable. Instead, the `ExecutableValidator` API (see
<<section-validating-executable-constraints>>) must be used to perform the validation, which is
often done using a method interception facility such as AOP, proxy objects etc.

Constraints may only be applied to instance methods, i.e. declaring constraints on static methods is
not supported. Depending on the interception facility you use for triggering method validation,
additional restrictions may apply, e.g. with respect to the visibility of methods supported as
target of interception. Refer to the documentation of the interception technology to find out
whether any such limitations exist.

===== Cross-parameter constraints

Sometimes validation does not only depend on a single parameter but on several or even all
parameters of a method or constructor. This kind of requirement can be fulfilled with help of a
cross-parameter constraint.

Cross-parameter constraints can be considered as the method validation equivalent to class-level
constraints. Both can be used to implement validation requirements which are based on several
elements. While class-level constraints apply to several properties of a bean, cross-parameter
constraints apply to several parameters of an executable.

In contrast to single-parameter constraints, cross-parameter constraints are declared on the method
or constructor as you can see in <<example-using-cross-parameter-constraint>>. Here the cross-
parameter constraint `@LuggageCountMatchesPassengerCount` declared on the `load()` method is used to
ensure that no passenger has more than two pieces of luggage.

[[example-using-cross-parameter-constraint]]
.Declaring a cross-parameter constraint
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/crossparameter/Car.java[tags=include]
----
====

As you will learn in the next section, return value constraints are also declared on the method
level. In order to distinguish cross-parameter constraints from return value constraints, the
constraint target is configured in the `ConstraintValidator` implementation using the
`@SupportedValidationTarget` annotation. You can find out about the details in
<<section-cross-parameter-constraints>> which shows how to implement your own cross-parameter constraint.

In some cases a constraint can be applied to an executable's parameters (i.e. it is a cross-
parameter constraint), but also to the return value. One example for this are custom constraints
which allow to specify validation rules using expression or script languages.

Such constraints must define a member `validationAppliesTo()` which can be used at declaration time to
specify the constraint target. As shown in <<example-specifying-constraint-target>> you apply the
constraint to an executable's parameters by specifying
`validationAppliesTo = ConstraintTarget.PARAMETERS`, while `ConstraintTarget.RETURN_VALUE` is used
to apply the constraint to the executable return value.

[[example-specifying-constraint-target]]
.Specifying a constraint's target
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/crossparameter/constrainttarget/Garage.java[tags=include]
----
====

Although such a constraint is applicable to the parameters and return value of an executable, the
target can often be inferred automatically. This is the case, if the constraint is declared on

* a void method with parameters (the constraint applies to the parameters)
* an executable with return value but no parameters (the constraint applies to the return value)
* neither a method nor a constructor, but a field, parameter etc. (the constraint applies to the
annotated element)

In these situations you don't have to specify the constraint target. It is still recommended to do
so if it increases readability of the source code. If the constraint target is not specified in
situations where it can't be determined automatically, a `ConstraintDeclarationException` is raised.

==== Return value constraints

The postconditions of a method or constructor are declared by adding constraint annotations to the
executable as shown in <<example-declaring-return-value-constraints>>.

[[example-declaring-return-value-constraints]]
.Declaring method and constructor return value constraints
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/returnvalue/RentalStation.java[tags=include]
----
====

The following constraints apply to the executables of `RentalStation`:

* Any newly created `RentalStation` object must satisfy the `@ValidRentalStation` constraint
* The customer list returned by `getCustomers()` must not be `null` and must contain at least on element
* The customer list returned by `getCustomers()` must no contain `null` objects

[NOTE]
====
As you can see in the above example, container element constraints are supported on method return value.
They are also supported on method parameters.
====

==== Cascaded validation

Similar to the cascaded validation of JavaBeans properties (see
<<section-object-graph-validation>>), the `@Valid` annotation can be used to mark executable
parameters and return values for cascaded validation. When validating a parameter or return value
annotated with `@Valid`, the constraints declared on the parameter or return value object are
validated as well.

In <<example-cascaded-executable-validation>>, the `car` parameter of the method `Garage#checkCar()` as
well as the return value of the `Garage` constructor are marked for cascaded validation.

[[example-cascaded-executable-validation]]
.Marking executable parameters and return values for cascaded validation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/cascaded/Garage.java[tags=include]
----

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

When validating the arguments of the `checkCar()` method, the constraints on the properties of the
passed `Car` object are evaluated as well. Similarly, the `@NotNull` constraint on the name field of
`Garage` is checked when validating the return value of the `Garage` constructor.

Generally, the cascaded validation works for executables in exactly the same way as it does for
JavaBeans properties.

In particular, `null` values are ignored during cascaded validation (naturally this can't happen
during constructor return value validation) and cascaded validation is performed recursively, i.e.
if a parameter or return value object which is marked for cascaded validation itself has properties
marked with `@Valid`, the constraints declared on the referenced elements will be validated as well.

Same as for fields and properties, cascaded validation can also be declared on container
elements (e.g. elements of collections, maps or custom containers) of return values and parameters.

In this case, each element contained by the container gets validated.
So when validating the arguments of the `checkCars()` method in
<<example-cascaded-executable-validation-container-elements>>, each element instance of the passed list
will be validated and a `ConstraintViolation` created when any of the contained `Car` instances is invalid.

[[example-cascaded-executable-validation-container-elements]]
.Container elements of method parameter marked for cascaded validation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/cascaded/containerelement/Garage.java[tags=include]
----
====

[[section-method-constraints-inheritance-hierarchies]]
==== Method constraints in inheritance hierarchies

When declaring method constraints in inheritance hierarchies, it is important to be aware of the
following rules:

* The preconditions to be satisfied by the caller of a method may not be strengthened in subtypes
* The postconditions guaranteed to the caller of a method may not be weakened in subtypes

These rules are motivated by the concept of _behavioral subtyping_ which requires that wherever a
type `T` is used, also a subtype `S` of `T` may be used without altering the program's behavior.

As an example, consider a class invoking a method on an object with the static type `T`. If the
runtime type of that object was `S` and `S` imposed additional preconditions, the client class might
fail to satisfy these preconditions as is not aware of them. The rules of behavioral subtyping are
also known as the http://en.wikipedia.org/wiki/Liskov_substitution_principle[Liskov
substitution principle].

The Jakarta Validation specification implements the first rule by disallowing parameter constraints on
methods which override or implement a method declared in a supertype (superclass or interface).
<<example-illegal-parameter-constraints>> shows a violation of this rule.

[[example-illegal-parameter-constraints]]
.Illegal method parameter constraint in subtype
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/inheritance/parameter/Vehicle.java[tags=include]
----

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

The `@Max` constraint on `Car#drive()` is illegal since this method implements the interface method
`Vehicle#drive()`. Note that parameter constraints on overriding methods are also disallowed, if the
supertype method itself doesn't declare any parameter constraints.

Furthermore, if a method overrides or implements a method declared in several parallel supertypes
(e.g. two interfaces not extending each other or a class and an interface not implemented by that
class), no parameter constraints may be specified for the method in any of the involved types. The
types in <<example-illegal-parameter-constraints-parallel-types>> demonstrate a violation of that
rule. The method `RacingCar#drive()` overrides `Vehicle#drive()` as well as `Car#drive()`.
Therefore the constraint on `Vehicle#drive()` is illegal.

[[example-illegal-parameter-constraints-parallel-types]]
.Illegal method parameter constraint in parallel types of a hierarchy
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/inheritance/parallel/Vehicle.java[tags=include]
----

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

[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/inheritance/parallel/RacingCar.java[tags=include]
----
====

The previously described restrictions only apply to parameter constraints. In contrast, return value
constraints may be added in methods overriding or implementing any supertype methods.

In this case, all the method's return value constraints apply for the subtype method, i.e. the
constraints declared on the subtype method itself as well as any return value constraints on
overridden/implemented supertype methods. This is legal as putting additional return value
constraints in place may never represent a weakening of the postconditions guaranteed to the caller
of a method.

So when validating the return value of the method `Car#getPassengers()` shown in
<<example-return-value-constraints-in-hierarchy>>, the `@Size` constraint on the method itself as well
as the `@NotNull` constraint on the implemented interface method `Vehicle#getPassengers()` apply.

[[example-return-value-constraints-in-hierarchy]]
.Return value constraints on supertype and subtype method
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/inheritance/returnvalue/Vehicle.java[tags=include]
----

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

If the validation engine detects a violation of any of the aforementioned rules, a
`ConstraintDeclarationException` will be raised.

[NOTE]
====
The rules described in this section only apply to methods but not constructors. By definition,
constructors never override supertype constructors. Therefore, when validating the parameters or the
return value of a constructor invocation only the constraints declared on the constructor itself
apply, but never any constraints declared on supertype constructors.
====

[TIP]
====
Enforcement of these rules may be relaxed by setting the configuration parameters contained in
the `MethodValidationConfiguration` property of the `HibernateValidatorConfiguration` before creating
the `Validator` instance. See also <<section-method-validation-prerequisite-relaxation>>.
====

[[section-validating-executable-constraints]]
=== Validating method constraints

The validation of method constraints is done using the `ExecutableValidator` interface.

In <<section-obtaining-executable-validator>> you will learn how to obtain an `ExecutableValidator`
instance while <<section-executable-validator-methods>> shows how to use the different methods
offered by this interface.

Instead of calling the `ExecutableValidator` methods directly from within application code, they are
usually invoked via a method interception technology such as AOP, proxy objects, etc. This causes
executable constraints to be validated automatically and transparently upon method or constructor
invocation. Typically a `ConstraintViolationException` is raised by the integration layer in case any
of the constraints is violated.

[[section-obtaining-executable-validator]]
==== Obtaining an `ExecutableValidator` instance

You can retrieve an `ExecutableValidator` instance via `Validator#forExecutables()` as shown in
<<example-obtaining-executable-validator>>.

[[example-obtaining-executable-validator]]
.Obtaining an `ExecutableValidator` instance
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/validation/CarTest.java[tags=setUpValidator]
----
====

In the example the executable validator is retrieved from the default validator factory, but if
required you could also bootstrap a specifically configured factory as described in
<<chapter-bootstrapping>>, for instance in order to use a specific parameter name provider
(see <<section-parameter-name-provider>>).

[[section-executable-validator-methods]]
==== `ExecutableValidator` methods

The `ExecutableValidator` interface offers altogether four methods:

* `validateParameters()` and `validateReturnValue()` for method validation
* `validateConstructorParameters()` and `validateConstructorReturnValue()` for constructor validation

Just as the methods on `Validator`, all these methods return a `Set<ConstraintViolation>` which contains
a `ConstraintViolation` instance for each violated constraint and which is empty if the validation
succeeds. Also all the methods have a var-args groups parameter by which you can pass the validation
groups to be considered for validation.

The examples in the following sections are based on the methods on constructors of the `Car` class
shown in <<example-executable-validator-class-car>>.

[[example-executable-validator-class-car]]
.Class `Car` with constrained methods and constructors
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/validation/Car.java[tags=include]
----
====

===== `ExecutableValidator#validateParameters()`

The method `validateParameters()` is used to validate the arguments of a method invocation.
<<example-executable-validator-validate-parameters>> shows an example. The validation results in a
violation of the `@Max` constraint on the parameter of the `drive()` method.

[[example-executable-validator-validate-parameters]]
.Using `ExecutableValidator#validateParameters()`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/validation/CarTest.java[tags=validateParameters]
----
====

Note that `validateParameters()` validates all the parameter constraints of a method, i.e. constraints
on individual parameters as well as cross-parameter constraints.

===== `ExecutableValidator#validateReturnValue()`

Using `validateReturnValue()` the return value of a method can be validated. The validation in
<<example-executable-validator-validate-return-value>> yields one constraint violation since the
`getPassengers()` method is expected to return at least one `Passenger` instance.

[[example-executable-validator-validate-return-value]]
.Using `ExecutableValidator#validateReturnValue()`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/validation/CarTest.java[tags=validateReturnValue]
----
====

===== `ExecutableValidator#validateConstructorParameters()`

The arguments of constructor invocations can be validated with `validateConstructorParameters()` as
shown in method <<example-executable-validator-validate-constructor-parameters>>. Due to the
`@NotNull` constraint on the `manufacturer` parameter, the validation call returns one constraint
violation.

[[example-executable-validator-validate-constructor-parameters]]
.Using `ExecutableValidator#validateConstructorParameters()`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/validation/CarTest.java[tags=validateConstructorParameters]
----
====

===== `ExecutableValidator#validateConstructorReturnValue()`

Finally, by using `validateConstructorReturnValue()` you can validate a constructor's return value. In
<<example-executable-validator-validate-constructor-return-value>>, `validateConstructorReturnValue()`
returns one constraint violation, since the `Car` instance returned by the constructor doesn't satisfy
the `@ValidRacingCar` constraint (not shown).

[[example-executable-validator-validate-constructor-return-value]]
.Using `ExecutableValidator#validateConstructorReturnValue()`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/validation/CarTest.java[tags=validateConstructorReturnValue]
----
====

==== `ConstraintViolation` methods for method validation

In addition to the methods introduced in <<section-constraint-violation-methods>>,
`ConstraintViolation` provides two more methods specific to the validation of executable parameters
and return values.

`ConstraintViolation#getExecutableParameters()` returns the validated parameter array in case of
method or constructor parameter validation, while `ConstraintViolation#getExecutableReturnValue()`
provides access to the validated object in case of return value validation.

All the other `ConstraintViolation` methods generally work for method validation in the same way as
for validation of beans. Refer to the
{bvApiDocsUrl}?jakarta/validation/metadata/BeanDescriptor.html[JavaDoc]
to learn more about the behavior of the individual methods and their return values during bean and
method validation.

Note that `getPropertyPath()` can be very useful in order to obtain detailed information about the
validated parameter or return value, e.g. for logging purposes. In particular, you can retrieve name
and argument types of the concerned method as well as the index of the concerned parameter from the
path nodes. How this can be done is shown in <<example-executable-validation-property-path>>.

[[example-executable-validation-property-path]]
.Retrieving method and parameter information
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/validation/CarTest.java[tags=retrieveMethodAndParameterInformation]
----
====

The parameter name is determined using the current `ParameterNameProvider` (see
<<section-parameter-name-provider>>).

[[section-builtin-method-constraints]]
=== Built-in method constraints

In addition to the built-in bean and property-level constraints discussed in
<<section-builtin-constraints>>, Hibernate Validator currently provides one method-level constraint,
`@ParameterScriptAssert`. This is a generic cross-parameter constraint which allows to implement
validation routines using any JSR 223 compatible ("Scripting for the Java^TM^ Platform") scripting
language, provided an engine for this language is available on the classpath.

To refer to the executable's parameters from within the expression, use their name as obtained from
the active parameter name provider (see <<section-parameter-name-provider>>).
<<example-parameterscriptassert>> shows how the validation logic of the `@LuggageCountMatchesPassengerCount`
constraint from <<example-using-cross-parameter-constraint>> could be expressed with the help of
`@ParameterScriptAssert`.

[[example-parameterscriptassert]]
.Using `@ParameterScriptAssert`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter03/parameterscriptassert/Car.java[tags=include]
----
====
