In this case, the @ModelAttribute annotation @ModelAttribute used to identify the object that Spring should add as an attribute of the model. Model attributes are an abstraction of HttpServletRequest attributes. Basically, these are objects identified by some key that will find their way in the HttpServletRequest attributes. You can do this by manually adding the attribute using Model#addAttribute(String, Object) , have the annotated @ModelAttribute method @ModelAttribute or annotate the method parameter using @ModelAttribute .
What you need to understand is how Spring resolves handler method parameters and introduces arguments. To do this, use the HandlerMethodArgumentResolver interface. There are several implementation classes (see Javadoc), and each of them is responsible for resolveArgument() , returning the argument that Spring will use to invoke() your handler method through reflection. Spring will only call the resolveArgument() method if the HandlerMethodArgumentResolver method supportsParameter() returns true for a particular parameter.
The implementation of the HandlerMethodArgumentResolver in question is here ServletModelAttributeMethodProcessor , which extends from ModelAttributeMethodProcessor , which states
It resolves method arguments annotated with @ModelAttribute and processes the return values from methods annotated with @ModelAttribute.
Spring (3.2) will register this HandlerMethodArgumentResolver and others
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); // Annotation-based argument resolution resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters())); resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters())); resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); // Type-based argument resolution resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(getMessageConverters())); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // Custom arguments if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); } // Catch-all resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers; }
When Spring needs to call the handler method, it will iterate over the parameter types and through the list above and use the first one that supportsParameter() .
Note that two instances of ServletModelAttributeMethodProcessor are added (one after the comment //catch all ). ModelAttributeMethodProcessor has an annotationNotRequired field that tells it whether it should look for @ModelAttribute or not. The first instance should look for @ModelAttribute , the second should not. Spring does this so that you can register your own instances of HandlerMethodArgumentResolver , see comment // Custom arguments .
In particular
@RequestMapping(value = "/", method = RequestMethod.POST) public String sayHello(Person person, Model model) { model.addAttribute("person", person); return "home"; }
In this case, it doesn't matter if your Person parameter is annotated or not. A ModelAttributeMethodProcessor allow it and bind the form fields, i.e. query parameters into instance fields. You do not even need to add it to model , since the ModelAttributeMethodProcessor class will handle this.
In your showHelloPage() method
model.addAttribute("person", new Person());
required with taglib <form> . The way it resolves its input fields.
So my question is: what is "ModelAttribute", anonnatation?
To automatically add the specified parameter (or method return value) to the model.
Can I omit the "modelAttribute" attribute on a form?
No, the form binding looks for an object in model and associates its fields with html input elements.
And the second part, what is the way (possibly an annotation) to make the form automatically bind the values of the input data to the corresponding properties of the bean (which will be declared as a parameter of the method)? Without the need to add an empty bean before submitting the form (how should I do it now).
A Spring <form> tag latches onto a model attribute object and uses its fields to create input and label elements. It doesn't matter how the object ended up in the model as long as it did. If it cannot find the model attribute with the name (key) you specified, it throws exceptions, as you saw.
<form:form method="post" modelAttribute="person">
An alternative to providing an empty bean is to create html yourself. Everything Spring <form> uses bean field names to create an input element. So this is
<form:form method="post" modelAttribute="person"> <form:label path="firstName">First name</form:label> <form:input path="firstName" />
It creates something like
<form method="post" action="[some action url]"> <label for="firstName">First name<label> <input type="text" name="firstName" value="[whatever value firstName field had]" /> ...
Spring associates query parameters with instance fields using the name attribute.