Pages

Wednesday, 29 October 2014

Partial Form Validation With Spring/Hibernate Validator (Using the Validated Annotation)

Use Case:
The default behavior of the @Valid annotation in a spring controller is to validate all the annotation. This works well when we need to validate all the input received from the form. This is true for most of the cases. But there can arise a scenario when we need to implement a multistep form, where the data is captured in multiple steps. For example lets take an scenario where we want to capture user details where the user detail can be split into multiple forms namely:
  • User Personal Details
  • User Address
  • Additional Details
Now if we define a single model for capturing all the details we would have to build our model catering to these three details separately. Instead we can have a single model containing all the details, and Group the validation for each type. This will enable us to capture the details into the same model in multiple steps and on each submission only the relevant fields can be validated.
User Details
Address
Contact Detail
First name
Hose Number
Mobile Number
Middle Name
Street
email id
Last Name
Locality
Phone Number
Date of Birth
City
Zip Code
Spring Version Required:
Springframework -- 4.1.1.RELEASE
Hibernate Validator -- 5.1.2.Final

Annotate with the Validator.

public class CustomerDetailsModel {
 
 public interface PersonalDetails{}
 public interface AddressDetails{}
        public interface ContacDetails{}


 long customerId;
 @NotNull(groups={PersonalDetails.class})
 @NotBlank(groups={PersonalDetails.class})
 @Size(max=35,groups={PersonalDetails.class})
 String firstName;
 @NotNull(groups={PersonalDetails.class})
 @NotBlank(groups={PersonalDetails.class})
 @Size(max=35,groups={PersonalDetails.class})
 @Size(max=35,groups={PersonalDetails.class})
 String middleName;
 String lastName;
 @Past(groups={PersonalDetails.class})
 Date dateOfBirth;

 @Size(max=20,groups={ContacDetails.class})
 String mobileNumber;
 @NotNull(groups={ContacDetails.class})
 @NotBlank(groups={ContacDetails.class})
 @Email(groups={ContacDetails.class})
 @Size(max=100,groups={ContacDetails.class})
 String emailId;

 @Size(max=20,groups=AddressDetails.class)
 String houseNumber;
 @Size(max=20,groups=AddressDetails.class)
 String street;
 int zipCode;
 @Size(max=30,groups=AddressDetails.class)
 String city;
 
        //..... Gettrs and setters goes here

        
}

One can notice that there are three validation groups defined in the model and corresponding to each an interface is defined in the class.

  • PersonalDetails
  • AddressDetails
  • ContactDetails
The interface can be defined either within the class or it can be defined independently. The purpose of the  Interface is to differentiate the various groups.

Using the Group Validation in a Controller:
Using the controller group validation with the controller is very simple. 

        //Capture and Validate personal Detail
 @RequestMapping(value = "/customer/updatepersonalDetails", method = RequestMethod.POST)
 @ResponseBody
 public CustomerDetailsModel updatePersonalDetail(
   @RequestBody @Validated({CustomerDetailsModel.PersonalDetails.class}) CustomerDetailsModel  customerDetails) {
  
 }
        //Capture and Validate Address Detail
 @RequestMapping(value = "/customer/updateaddressDetails", method = RequestMethod.POST)
 @ResponseBody
 public CustomerDetailsModel updateAddressDetail(
   @RequestBody @Validated({CustomerDetailsModel.AddressDetails.class}) CustomerDetailsModel  customerDetails) {
  
 }
        //Capture and Validate Contact Detail Only
 @RequestMapping(value = "/customer/updatecontactDetails", method = RequestMethod.POST)
 @ResponseBody
 public CustomerDetailsModel updateAddressDetail(
   @RequestBody @Validated({CustomerDetailsModel.ContactDetails.class}) CustomerDetailsModel  customerDetails) {
  
 }


Note: More than one validation group can be grouped together by just including the same, e.g  ContactDetails and AddressDetails can be grouped in the Controller using the below mentioned syntax:
@Validated({CustomerDetailsModel.AddressDetails.class,CustomerDetailsModel.ContactDetails.class})
Conclusion:
Using @Validated along with the Group validator can provide you with a partial validation of the model instead of the full model.

Reference:

  1. https://docs.jboss.org/hibernate/validator/4.0.1/reference/en/html/validator-usingvalidator.html#example-group-interfaces



No comments:

Post a Comment