Hibernate Validator is the reference implementation for the Bean Validation specification. For more information, see Hibernate Validator on hibernate.org.

With the release of Hibernate Validator 5.1.0.Alpha1 just out, it is time to pick up on the Bean Validation 1.1 spotlight series and cast a light onto method validation. Long time Hibernate Validator users know that method validation is part of Validator since version 4.2, however only as a provider specific featue. Bean Validation 1.1 makes method validation now part of the specification.

But what is method validation? Method validation is the ability to place constraint annotations onto methods or constructors and/or their parameters. Here is an example:

public class User {
     public User(@NotNull @Size(max = 40) String firstName, @NotNull @Size(max = 40) String lastName) {
        // ...
     }

     @NotNull
     @Valid
     public Order placeOrder(@NotNull @Valid Item item) {
          // ...
     }

     @PasswordsMatch
     public void resetPassword( @NotNull String password, @NotNull String passwordConfirmation) {
          // ...
     }

     // ...
}

The constraints describe that whenever the constructor of User is called, firstName and lastName cannot be null and neither can exceed 40 characters. Also, whenever the user places an order, the provided Item instance cannot be null and must be valid. Valid in this context means that the instance itself passes the validation of all its property (constraints placed on fields and getters) and class level constraints. The returned Order instance of the placeOrder() call is a non null instance which also passes all bean constrains for this type. Last but not least, if the user resets his password, the new password and the password confirmation cannot be null and they have to match. The latter is expressed via a so called cross parameter constraint - @PasswordMatch.

Overall, the shown constraints define the pre- and postconditions for a given method or constructor call. This is commonly known as programming by contract which allows to make the specification of the these constraints part of the method. It also avoids code duplication, since these checks don't have to be implemented redundantly in the body of the methods.

But how do these constraints get validated then? Bean Validation offers for this purpose ExecutableValidator which can be retrieved from a Validator instance via Validator.forExecutables(). This ExecutableValidator offers the methods to validate method/constructor parameters and return values. This in itself, however, is not very helpful for an application developer. She would have to write the required code to handle the validation herself which is not a trivial task. Instead the intention is that frameworks and libraries provide the integration for the application developer via some sort of AOP, interceptor or proxy based approach. That way, method validation occurs transparently upon invocation of constrained methods or constructors, throwing a ConstraintViolationException whenever one more more constraints are violated. An example of this type of integration is the Java EE 7 framework.

In Java EE 7 all CDI managed beans are automatically method validated. All you have to do is to place constraints on methods or constructors and their parameters. CDI will then, via its interceptor capabilities, evaluate all method validation constraints. In this context it is important to know that Bean Validation does not validate getters (method name starts with get, has a return type and no parameters or starts with is, is returning boolean and has no parameters) per default. This is to avoid conflicts with the validation of bean constraints. This behaviour can be configured via the use of @ValidateOnExecution or in validation.xml using default-validated-executable-types. The specification contains all the details and also gives some examples.

Last but not least, another caveat. When using method validation constraints within class hierarchies, the specification demands that the Liskov substitution principle holds. Formally this means that a method's preconditions (as represented by parameter constraints) must not be strengthened and its postconditions (as represented by return value constraints) must not be weakened in sub-types. Concretely it implies that in sub-types no parameter constraints can be declared on overridden or implemented methods. Also parameters cannot be marked for cascaded validation. Instead, all parameter constraints must be defined at the method's root within the hierarchy. The Bean Validation implementation will throw a ConstraintDeclarationException if the Liskov substitution principle is violated. The complete set of rules can be found in Method constraints in inheritance hierarchies of the specification.

I hope this blog helped to shine some light on the biggest new feature of Bean Validation 1.1 - method validation. If you have questions, leave a comment, contact us via the forum or chat to us in IRC.

Happy validating!

P.S. We will talk about the changes to the metadata and javax.validation.Path API related to method validation in another post. We also will have a closer look at the details of implementing cross parameter constraints. Stay tuned.


Back to top