JSR 303 – BEAN VALIDATION – Nested Validation

Following up from my previous post about JSR 303 – Bean Validation, we will see how to apply it to any nested property and how to display validation error on screen using Spring MVC’s JSP tags

1. Bean Validation on Nested Property

Recall that to validate any property, we only need to put a Constraint annotation on top of its declaration. Example of common constraints are @NotEmpty, @Pattern, @Email.One thing in common of these constraints are that the applied property has to be of type String.

But if you have a bean called Person with an Address property and using these provided constraints, how do you validate that houseNumber, streetName are mandatory while country, province is not?


public class Person {
   @NotEmpty
   private String fullName;

   @Email
   private String email;

   @Pattern (regexp = "[0-9]+")
   private String telNo;

   @NotNull
   private Address address;
}

class Address {
   private String houseNumber;

   private String streetName;

   private String province;

   private String country;
}

You can create a custom constraint (e.g. @ValidAddress) – we will explore this option in the next post. Or you can use @Valid on the address property in combination of other constraints inside Address class. A valid example would be:


public class Person {
   @NotEmpty
   private String fullName;

   @Email
   private String email;

   @Pattern (regexp = "[0-9]+")
   private String telNo;

   @NotNull
   @Valid
   private Address address;
}

class Address {
   @NotEmpty
   private String houseNumber;

   @NotEmpty
   private String streetName;

   private String province;

   private String country;
}

@Valid constraint will instruct the Bean Validator to delve to the type of its applied property and validate all constraints found there. In above example, the validator, when seeing a @Valid constraint on address property, will explore the Address class and validate all JSR 303 Constraints found inside. Because houseNumber and streetName are marked with @NotEmpty constraints, they are mandatory; province and country on the other hand are optional.

2. Display Validation Error Using Spring MVC’s JSP Tags

Spring MVC tag library (<%@ taglib prefix=”form” uri=”http://www.springframework.org/tags/form&#8221; %>) offers a consistent way to display and collect input form. For our purpose, the tag used to display validation error is errors

Assume an instance of Person is an backing object of an input form and is displayed using Spring MVC tag.

Validation error on fullName field can be make visible by below code:

<form:errors path="fullName" />

Validation error on nested field such as houseNumber of address property can be make visible by specifying the full path:

<form:errors path="address.houseNumber" />

8 comments

  1. […] far, we have learn the basic and a not-so-common nested usage of JSR 303 Bean Validation, it’s time to learn how the declarative validation rule was […]

  2. I’ve observed that cascade validation goes from top to bottom.
    do you know how does one can make this in reverse mode?
    I’d like to use this with fail_fast, to avoid further validations in case that nested validation is violated.

    thanks in advance!

  3. Hi Lecaros, thanks for your comment. it’s a nice feature to have, but i don’t think there is an nice way to do it.

    For me I would do it this way:

    1. I will need to set an validation order with fail_fast one being validated early. This is where it lost its niceness: the spec does not support orderring yet! You can found different work-around here: http://beanvalidation.org/proposals/BVAL-248/

    2. Then apply @Valid annotation
    3. Recursively repeat step 1 and 2 to the nested class.

    The reason we need a validation order is because of the fail_fast requirement.

    Hope it helps.

  4. Hi Huynt,
    I’ve finally got with a solution. Using marker annotations and a @GroupSequence annotation.
    I’ve made two interfaces First and Last. Then an interface called GroupOrder, which is annotated with @GroupSequence({First.class, Last.class}).
    After this, I just add any of those Interfaces in my annotations, say @NotNull(groups=First.class)
    :)

  5. oh, just realized that is the same you mentioned in your link :D

  6. it is not working in this case: Sample code:
    public class AccountRegisterForm {
    @NotNull
    @Valid
    public IContact billContact;
    }

    Contact class is:
    @NotNull
    @Valid
    private Person person;
    @NotNull
    @Valid
    Person class is:
    @NotEmpty
    private String firstName;
    In controller i am getting error in bindingResult:
    @RequestMapping(method = {RequestMethod.POST})
    public String submit(HttpServletRequest request, HttpServletResponse response,
    @Valid @ModelAttribute(RequestParams.ACCOUNT_FORM) AccountRegisterForm accountRegisterForm,
    BindingResult bindingResult) throws Exception {

    In Jsp I am printing the error message like this:

    But not getting error message.

    Errpr object is printing the message:
    Field error in object ‘accountRegisterForm’ on field ‘billContact’: rejected value [null]; codes [NotNull.accountRegisterForm.billContact,NotNull.billContact,NotNull.org.marketlive.entity.account.IContact,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [accountRegisterForm.billContact,billContact]; arguments []; default message [billContact]]; default message [may not be null]

  7. Hi Brijesh,

    Are you able to verify if billContact is indeed not null? You may try to remove the @Valid from controller’s method in order to check.

    The reason I’m asking is to determine if the error is indeed related to Bean Validation, or is due to Spring’s auto-mapping HTTP parameters to Java object

  8. Nice article Thanks it solved the my problem

Leave a comment