Is there a way to use more than 1 validator with Spring 3 annotated controller?

I have a Spring 2.x controller that extends SimpleFormController

that is deprecated in Spring 3 in favor of annotated controllers. So I am trying to convert it to use @Controller

, with @InitBinder

and @Valid

for form validation. However, I can't seem to find a way to use multiple validators with the Spring 3.x controller. How to do it?

This is what my controller bean def looks like:

<bean name="/s/account" class="mywork.AccountSettingsController"
    p:formView="forms/account"
    p:successView="redirect:/app/s/account"
    p:commandName="accountSettingsForm">
    <property name="validators">
        <list>
            <ref bean="emailFormatValidator" />
            <ref bean="uniqueEmailValidator" />
            <ref bean="changeEmailValidator" />
            <ref bean="passwordWithConfirmationValidator" />
            <ref bean="changePasswordValidator" />
        </list>
    </property>
</bean>

      

This is the controller for the page that allows the user to change their email and password. The beans validator is legacy code, but I assume they have been split into separate classes for better reuse.

I'm trying to move the whole thing into a controller class using annotations:

@Controller
@Secured({BaseController.ROLE_LOGGED_IN})
@RequestMapping("/s/account")
public class AccountSettingsController extends BaseController {
    private static final String FORM_URL = "/forms/account";
    private static final String FORM_NAME = "accountSettingsForm";

    @InitBinder(FORM_NAME)
    public void initBinder(WebDataBinder binder) {
        // TODO: how to inject > 1 validator for the form?
        binder.setValidator(...);
    }

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView get() {
        ChangePasswordOrEmailForm form = new ChangePasswordOrEmailForm();
        ...
        return new ModelAndView(FORM_URL, FORM_NAME, form);
    }
    ...
}

      

As far as I can tell, Spring 3 assumes a 1 to 1 relationship between: Controller-Form-WebDataBinder-Validator. I could create a composite validator that concatenates 5 separate beans validators and delegates calls to them Validator#supports()

and Validator#validate()

, but is this really the best solution?

+3


source to share


3 answers


This was an old problem.

Adding a comment here:



After spring 3.2.1.RELEASE, DataBinder # addValidators (Validator ... validators) is available .

+1


source


Another one I thought was supposed to have a ValidatorFacade which in turn calls all the other validators one by one, this way you don't need to type, rather attach the ValidatorFacade with initBinder and @Valid before your form bean automatically call the ValidatorFacade function and everything that will be done automatically. Just a thought.



+3


source


The best solution I can think of is to inject a collection of validators and manually loop through them yourself. So for now I removed the initBinder()

controller from my class, and this is what I added:

private List<Validator> accountSettingsValidators;

// Maps & Collections can't be @Autowired (by type OR name), so use the JSR 250 @Resource annotation to autowire by name
@Resource
public void setAccountSettingsValidators(List<Validator> accountSettingsValidators) {
    this.accountSettingsValidators = accountSettingsValidators;
}

@RequestMapping(method = RequestMethod.POST)
protected ModelAndView processSubmit(HttpServletRequest request,
                                     @ModelAttribute(FORM_NAME) ChangePasswordOrEmailForm form,
                                     BindingResult bindingResult) {
    for (Validator validator : this.accountSettingsValidators) {
        ValidationUtils.invokeValidator(validator, form, bindingResult);
    }

    if (bindingResult.hasErrors()) {
        return new ModelAndView(FORM_URL, FORM_NAME, form);
    }

    // process validated form
}

      

In my formControllers.xml

Spring configuration, I create a list of validators for input:

<util:list id="accountSettingsValidators">
    <ref bean="emailFormatValidator" />
    <ref bean="uniqueEmailValidator" />
    <ref bean="changeEmailValidator" />
    <ref bean="passwordWithConfirmationValidator" />
    <ref bean="changePasswordValidator" />
</util:list>

      

0


source







All Articles