Maxiq
Maxiq

Reputation: 133

Did I understand @ModelAttribute right?

I need help with understanding following example with @ModelAttribute from Spring documentation: (method populatePetTypes())

@Controller
@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
@SessionAttributes("pet")
public class EditPetForm {

    // ...

    @ModelAttribute("types")
    public Collection<PetType> populatePetTypes() {
        return this.clinic.getPetTypes();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processSubmit(
            @ModelAttribute("pet") Pet pet,
            BindingResult result, SessionStatus status) {

        new PetValidator().validate(pet, result);
        if (result.hasErrors()) {
            return "petForm";
        }
        else {
            this.clinic.storePet(pet);
            status.setComplete();
            return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
        }
    }

}

I am undestood this like additional "value" which our Model object could get in the whole current controller. Is it true?

I am trying to do some test, by adding that code to my controller:

@ModelAttribute("user")
public Integer getKod(){
    return new Integer(123321);
}

another method is:

@RequestMapping("/register")
public String register(Map<String, Object> map, @ModelAttribute("user") MyUser user, BindingResult result) {
...
}

and now I am try just show "kod" into my form:

<form:form method="post" action="" commandName="user">
(...)
        <form:label path="kod">kod</form:label>:
        <form:input path="kod"/>
(...)
</form:form>

but I got:

java.lang.IllegalArgumentException: java.lang.ClassCastException@229d7c57

please help!

Upvotes: 2

Views: 2565

Answers (1)

Affe
Affe

Reputation: 47994

The annotation means different things depending on where you put it.

@ModelAttribute on a method tells Spring to put the method's return vlaue into the Map, under that name. It is not telling it to do property binding on that object. So you're putting an Integer called "user" in the Map.

@ModelAttribute on a parameter tells Spring "Find something in the map with this name, and assign it to this method parameter."

So you put an Integer in the map under the name "user" then asked Spring to assign to an Object of type MyUser. Of course Integer cannot be cast to MyUser!

I think you're confusing the 'Model' in the classic MVC sense, which is your MyUser, with Spring's ModelMap, which is all of the data that's available as part of the view. When the Spring controller refers to 'Model' it means the ModelMap of all things that are relevant to building the screen. Your MyUser object is one entry in that map, but there can be more other things that are also part of the screen in there. In spring-ese we would frequently refer to your MyUser as the 'Form Backing Object' because it's the actual binding target of your form.

For example, in the snippet you posted, the "types" list of PetTypes is part of the Spring ModelMap. It's reference data needed to build the view. But it's not an attribute of the 'Pet' object, which is the form backing object.

Upvotes: 3

Related Questions