Skip to content

Jakarta Validation

Jakarta Validation (formerly known as Jakarta Bean Validation) 3.1 mainly adds support for record types, which were introduced in Java SE 11.

Let's use an example to illustrate this.

// Customer.java
public record Customer(
    @NotBlank
    String firstName,
    @NotBlank
    String lastName,

    @NotNull
    Optional<@NotNull PhoneNumber> phoneNumber,

    @NotEmpty
    EmailAddress[] emailAddresses,

    @Valid
    Address address
) {
}

// Address.java
public record Address(
    @NotBlank
    String street,
    @NotBlank
    String city,
    String state,
    @NotBlank
    String zipCode
) {
}

// PhoneNumber.java
public record PhoneNumber(
    @NotBlank
    @Pattern(regexp = "\\d{3,4}")
    String countryCode,

    @NotBlank
    @Pattern(regexp = "\\d{3,11}")
    String number
) {
}

// EmailAddress.java
public record EmailAddress(
    @Email
    @NotBlank
    String email,
    @NotNull
    Boolean primary
) {
}

In a Java SE environment, simply add the Jakarta Validation implementation, eg, Hibernate Validator, to the classpath and initialize a Validator instance as follows:

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

Create a valid Customer instance and validate it using the validator.validate method:

var data = new Customer(
    "Foo",
    "Bar",
    Optional.of(new PhoneNumber("001", "3334445555")),
    new EmailAddress[]{
        new EmailAddress("foo@example.com", true),
        new EmailAddress("bar@example.com", false)
    },
    new Address("123 Main St", "Anytown", "CA", "12345")
);

var constraints = validator.validate(data);
LOGGER.info("Constraints: " + constraints);

In the above example, the constraints result is empty.

Now, create a new Customer instance with a null phone number:

var data = new Customer(
    "Foo",
    "Bar",
    Optional.empty(),
    new EmailAddress[]{
        new EmailAddress("foo@example.com", true),
        new EmailAddress("bar@example.com", false)
    },
    new Address("123 Main St", "Anytown", "CA", "12345")
);

var constraints = validator.validate(data);
LOGGER.info("Constraints: " + constraints);

When you run the code, the console will print the constraints as follows:

INFO: Constraints: [ConstraintViolationImpl{interpolatedMessage='must not be null', propertyPath=phoneNumber, rootBeanClass=class com.example.Customer, messageTemplate='{jakarta.validation.constraints.NotNull.message}'}]

Next, create another Customer instance without any emails:

var data = new Customer(
    "Foo",
    "Bar",
    Optional.of(new PhoneNumber("001", "3334445555")),
    new EmailAddress[]{},
    new Address("123 Main St", "Anytown", "CA", "12345")
);

var constraints = validator.validate(data);
LOGGER.info("Constraints: " + constraints);

You should see the following output in the console:

INFO: Constraints: [ConstraintViolationImpl{interpolatedMessage='must not be empty', propertyPath=emailAddresses, rootBeanClass=class com.example.Customer, messageTemplate='{jakarta.validation.constraints.NotEmpty.message}'}]

Now, create a new Customer with an address that does not have a zip code:

var data = new Customer(
    "Foo",
    "Bar",
    Optional.of(new PhoneNumber("001", "3334445555")),
    new EmailAddress[]{
        new EmailAddress("foo@example.com", true),
        new EmailAddress("bar@example.com", false)
    },
    new Address("123 Main St", "Anytown", "CA", null)
);

var constraints = validator.validate(data);
LOGGER.info("Constraints: " + constraints);

Run the code and you will see the following output in the console:

INFO: Constraints: [ConstraintViolationImpl{interpolatedMessage='must not be blank', propertyPath=address.zipCode, rootBeanClass=class com.example.Customer, messageTemplate='{jakarta.validation.constraints.NotBlank.message}'}]

The validator.validate method returns a set of ConstraintViolation objects, which describe the validation constraints for each property path. If the set is empty, it means the validation was successful.

Example Project

Download the example project from GitHub and explore it on your local system. The CustomerTest class contains all the examples shown in this article.