How to pass @RequestParam and @ModelAttribute in one form
Asked Answered
R

1

5

I would like to mix @RequestParam and @ModelAttribute in one spring form and controller.

Things that I do in my controller are as follows:

@RequestMapping("/user/edit/{userId}")
public ModelAndView editUser(@PathVariable String userId, 
    @ModelAttribute User user, BindingResult bindingResult,
    @RequestParam Set<String> groups) {

    if(bindingResults.hasErrors() {
        //return back to form and correct errors
    } else {
        //save data and get out of form 
    }
} 

There are simple User bean (id, firstName, lastName, etc) but without "groups" property. There is also simple Group bean (id, name, description) but without any connection with User. So on the logical level User and Group are totally separeted.

In my form, when editing User, there is a html SELECT element that contains ids of all groups. You can select multiple ids together with filling User data and send it to controller.

Until now, everything works pretty well. I get @ModelAttibute User properly filled. I also get @RequestParam Set[String] groups filled with selected ids (Strings).

Now I would like to do something more. I need to write something that instead of @RequestParam Set[String] groups will give me @RequestParam Set[Group] groups. Of course I can convert it directly in my controller method editUser(...) but it's not a nice solution. So I decided to write a custom @InitBinder method that will do it for me nicely and smoothly.

And tere the problem comes.

I wrote the initBinder as follows:

[...]
webDataBinder.registerCustomEditor(Set.class, "groups", new CustomCollectionEditor(Set.class) {
    @Override
    protected Object convertElement(Object element) {
        if (element instanceof GroupName) {
            return element;
        }

        if (element instanceof String) {
            Group group = userCatalog.loadGroup((String) element);
            return group.getGroupName();
        }

        return null;
    }
});
[...]

The problem is that there is absolutely no way to call this method. I put inside that some "debugging" System.out.println(...) but it doesn't print anything.

My question is: how to write a correct InitBinder that will be invoked in response to Strings array from html OPTION element and convert it to my Set of Users.

I changed some brackets to this [ and ] because it wasn't displayed.

Thank you for help.


meanwhile I came across on this topic: Custom property editors do not work for request parameters in Spring MVC?

and I think this is a key to the solution. In fact, as javadocs says, "field" argument is necessary only when using ModelAttibute (or form backing object which is the same...), but not for RequestParam. So is there any solution to use InitBinder together with RequestParam? Or I need to write a direct method in controller that converts ids to Set of Group objects?

Retroact answered 29/6, 2012 at 20:21 Comment(1)
Why does it have to be a request param? you could make one backing object for the entire form that contains a User and a collection of GroupsYellowthroat
S
0

Try registering your custom editor just against the Set.class type and leaving out the field name to see if that works.

webDataBinder.registerCustomEditor(Set.class, new CustomCol...

I have a suspicion that the field parameter denotes the property name of a ModelAttribute and not the request parameter name.

Alternatively, you could use a wrapper view model and use a second ModelAttribute parameter,

class GroupsViewModel {
    private List<Group> groups
    ...
}
Sidras answered 1/7, 2012 at 11:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.