59.2. Developing Services with Bean Validation

59.2.1. Annotating a Service Bean

Overview

The first step in developing a service with bean validation is to apply the relevant validation annotations to the Java classes or interfaces that represent your services. The validation annotations enable you to apply constraints to method parameters, return values, and class fields, which are then checked at run time, every time the service is invoked.

Validating simple input parameters

To validate the parameters of a service method—where the parameters are simple Java types—you can apply any of the constraint annotations from the bean validation API (javax.validation.constraints package). For example, the following code example tests both parameters for nullness (@NotNull annotation), whether the id string matches the \\d+ regular expression (@Pattern annotation), and whether the length of the name string lies in the range 1 to 50:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
...
@POST
@Path("/books")
public Response addBook(
        @NotNull @Pattern(regexp = "\\d+") @FormParam("id") String id,
        @NotNull @Size(min = 1, max = 50) @FormParam("name") String name) {
    // do some work
    return Response.created().build();
}

Validating complex input parameters

To validate complex input parameters (object instances), apply the @Valid annotation to the parameter, as shown in the following example:
import javax.validation.Valid;
...
@POST
@Path("/books")
public Response addBook( @Valid Book book ) {
    // do some work
    return Response.created().build();
}
The @Valid annotation does not specify any constraints by itself. When you annotate the Book parameter with @Valid, you are effectively telling the validation engine to look inside the definition of the Book class (recursively) to look for validation constraints. In this example, the Book class is defined with validation constraints on its id and name fields, as follows:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
...
public class Book {
    @NotNull @Pattern(regexp = "\\d+") private String id;
    @NotNull @Size(min = 1, max = 50) private String name;
 
    // ...
}

Validating return values (non-Response)

To apply validation to regular method return values (non-Response), add the annotations in front of the method signature. For example, to test the return value for nullness (@NotNull annotation) and to test validation constraints recursively (@Valid annotation), annotate the getBook method as follows:
import javax.validation.constraints.NotNull;
import javax.validation.Valid;
...
@GET
@Path("/books/{bookId}")
@Override   
@NotNull @Valid
public Book getBook(@PathParam("bookId") String id) {
    return new Book( id );     
}

Validating return values (Response)

To apply validation to a method that returns a javax.ws.rs.core.Response object, you can use the same annotations as in the non-Response case. For example:
import javax.validation.constraints.NotNull;
import javax.validation.Valid;
import javax.ws.rs.core.Response;
...
@GET
@Path("/books/{bookId}")
@Valid @NotNull
public Response getBookResponse(@PathParam("bookId") String id) {
    return Response.ok( new Book( id ) ).build();
}

59.2.2. Standard Annotations

Bean validation constraints

Table 59.1, “Standard Annotations for Bean Validation” shows the standard annotations defined in the Bean Validation specification, which can be used to define constraints on fields and on method return values and parameters (none of the standard annotations can be applied at the class level).

Table 59.1. Standard Annotations for Bean Validation

AnnotationApplicable toDescription
@AssertFalseBoolean, booleanChecks that the annotated element is false.
@AssertTrueBoolean, booleanChecks that the annotated element is true.
@DecimalMax(value=, inclusive=)BigDecimal, BigInteger, CharSequence, byte, short, int, long and primitive type wrappersWhen inclusive=false, checks that the annotated value is less than the specified maximum. Otherwise, checks that the value is less than or equal to the specified maximum. The value parameter specifies the maximum in BigDecimal string format.
@DecimalMin(value=, inclusive=)BigDecimal, BigInteger, CharSequence, byte, short, int, long and primitive type wrappersWhen inclusive=false, checks that the annotated value is greater than the specified minimum. Otherwise, checks that the value is greater than or equal to the specified minimum. The value parameter specifies the minimum in BigDecimal string format.
@Digits(integer=, fraction=)BigDecimal, BigInteger, CharSequence, byte, short, int, long and primitive type wrappersChecks whether the annotated value is a number having up to integer digits and fraction fractional digits.
@Futurejava.util.Date, java.util.CalendarChecks whether the annotated date is in the future.
@Max(value=)BigDecimal, BigInteger, CharSequence, byte, short, int, long and primitive type wrappersChecks whether the annotated value is less than or equal to the specified maximum.
@Min(value=)BigDecimal, BigInteger, CharSequence, byte, short, int, long and primitive type wrappersChecks whether the annotated value is greater than or equal to the specified minimum.
@NotNullAny typeChecks that the annotated value is not null.
@NullAny typeChecks that the annotated value is null.
@Pastjava.util.Date, java.util.CalendarChecks whether the annotated date is in the past.
@Pattern(regex=, flag=)CharSequenceChecks whether the annotated string matches the regular expression regex considering the given flag match.
@Size(min=, max=)CharSequence, Collection, Map and arraysChecks whether the size of the annotated collection, map, or array lies between min and max (inclusive).
@ValidAny non-primitive typePerforms validation recursively on the annotated object. If the object is a collection or an array, the elements are validated recursively. If the object is a map, the value elements are validated recursively.

59.2.3. Custom Annotations

Defining custom constraints in Hibernate

It is possible to define your own custom constraints annotations with the bean validation API. For details of how to do this in the Hibernate validator implementation, see the Creating custom constraints chapter of the Hibernate Validator Reference Guide.