About Rafal Borowiec

Rafal is an IT specialist with about 8 years of commercial experience, specializing in software testing and quality assurance, software development, project management and team leadership.

Validation groups in Spring MVC

logo-spring-io

Validation constraints in Bean Validation may be added to one or more groups via groups attribute. This allows you to restrict the set of constraints applied during validation. It can be handy in cases where some groups should be validated before others like e.g. in wizards. As of Spring MVC 3.1, automatic validation utilizing validation groups is possible with org.springframework.validation.annotation.Validated annotation. In this article I will use simple Spring MVC application to demonstrate how easily you can use validation groups to validate Spring’s MVC model attributes.

Form

Let’s start with the form class that will be validated in steps. Firstly, we define interfaces that represents constraint groups:

public class Account implements PasswordAware {

    interface ValidationStepOne {
        // validation group marker interface
    }

    interface ValidationStepTwo {
        // validation group marker interface
    }
}

Validation contraints

Next we assign constraint to groups. Remember, if you don’t provide groups the default one will be used. Please also note @SamePasswords, @StrongPassword – custom constraints, that must define groups attribute:

@SamePasswords(groups = {Account.ValidationStepTwo.class})
public class Account implements PasswordAware {

    @NotBlank(groups = {ValidationStepOne.class})
    private String username;

    @Email(groups = {ValidationStepOne.class})
    @NotBlank(groups = {ValidationStepOne.class})
    private String email;

    @NotBlank(groups = {ValidationStepTwo.class})
    @StrongPassword(groups = {ValidationStepTwo.class})
    private String password;

    @NotBlank(groups = {ValidationStepTwo.class})
    private String confirmedPassword;

    // getters and setters
}

Wizard

Having the Account, we can create a 3-step wizard @Controller that will let users create an account. In first step we will let Spring validate constraint in ValidationStepOne group:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "stepOne")
    public String stepOne(Model model) {
        model.addAttribute("account", new Account());
        return VIEW_STEP_ONE;
    }

    @RequestMapping(value = "stepOne", method = RequestMethod.POST)
    public String stepOne(@Validated(Account.ValidationStepOne.class) Account account, Errors errors) {
        if (errors.hasErrors()) {
            return VIEW_STEP_ONE;
        }
        return "redirect:stepTwo";
    }
}

To trigger validation with groups I used @Validated annotation. This annotation takes var-arg argument with groups’ types. The code @Validated(ValidationStepOne.class) triggers validation of constraint in ValidationStepOne group.

In the next step we will let Spring validate constraint in ValidationStepTwo group:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "stepTwo")
    public String stepTwo() {
        return VIEW_STEP_TWO;
    }

    @RequestMapping(value = "stepTwo", method = RequestMethod.POST)
    public String stepTwo(@Validated(Account.ValidationStepTwo.class) Account account, Errors errors) {
        if (errors.hasErrors()) {
            return VIEW_STEP_TWO;
        }
        return "redirect:summary";
    }
}

In the summary step we will confirm entered data and we will let Spring validate constraint of both groups:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "summary")
    public String summary() {
        return VIEW_SUMMARY;
    }

    @RequestMapping(value = "confirm")
    public String confirm(@Validated({Account.ValidationStepOne.class, Account.ValidationStepTwo.class}) Account account, Errors errors, SessionStatus status) {
        status.setComplete();
        if (errors.hasErrors()) {
            // did not pass full validation
        }
        return "redirect:start";
    }
}

Prior to Spring 3.1 you could trigger the validation manually. I described this in one of my previous posts: http://blog.codeleak.pl/2011/03/how-to-jsr303-validation-groups-in.html

Note: If you want to use validation groups without Spring, you need to pass groups to javax.validation.Validator#validate():

Validation groups without Spring

Validator validator = Validation
        .buildDefaultValidatorFactory().getValidator();
Account account = new Account();

// validate with first group
Set<ConstraintViolation<Account>> constraintViolations =
        validator.validate(account, Account.ValidationStepOne.class);
assertThat(constraintViolations).hasSize(2);

// validate with both groups
Set<ConstraintViolation<Account>> constraintViolations =
        validator.validate(account, Account.ValidationStepOne.class, Account.ValidationStepTwo.class);
assertThat(constraintViolations).hasSize(4);

This is also the easiest way to test validations:

public class AccountValidationTest {

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

    @Test
    public void shouldHaveFourConstraintViolationsWhileValidatingBothGroups() {
        Account account = new Account();
        Set<ConstraintViolation<Account>> constraintViolations = validator.validate(
                account, Account.ValidationStepOne.class, Account.ValidationStepTwo.class
        );
        assertThat(constraintViolations).hasSize(4);
    }

    @Test
    public void shouldHaveTwoConstraintViolationsWhileStepOne() {
        Account account = new Account();
        Set<ConstraintViolation<Account>> constraintViolations = validator.validate(
                account, Account.ValidationStepOne.class
        );
        assertThat(constraintViolations).hasSize(2);

    }
}

Testing validation with Spring Test

Testing validation with Spring Test offers more sophisticated way of testing if validation/binding failed. For the examples, have a look at my other blog post: Spring MVC Integration Testing: Assert the given model attribute(s) have global errors

Reference: Validation groups in Spring MVC from our JCG partner Rafal Borowiec at the Codeleak.pl blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


seven − = 0



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close