2

As said at this link under section Using @ModelAttribute on a method argument

An @ModelAttribute on a method argument indicates the argument should be retrieved from the model.

But i have observed that even without annotating UserDetail with @ModelAttribute , userDetail is populated correctly. Here is relevant code snippet

<form:form id="userForm" action="path/userDetail" method="post" commandName="userDetail"> @RequestMapping(value="/userDetail", method=RequestMethod.POST) public String processUserDetail(UserDetail userDetail, HttpServletRequest request, HttpServletResponse response, Locale locale) {} 

So my question does spring itself populate the project custom objects (in this case userDetail) present in handler method arguments even without annotating @ModelAttribute. I believe @ModelAttribute plays role while rendering view but while submission spring automatically populates the method argument if it is present in model ?

2 Answers 2

1

Does handler method resolves arguments even without annotating @ModelAttribute?

Yes, but what @ModelAttribute changes is the point when an appropriate resolving happens. What the framework does in the process of argument resolving is it takes each argument and iterates through the list of registered resolvers and once that it finds the first resolver that supports the argument it resolves it and moves to the next argument.

The resolver that handles model attributes is ServletModelAttributeMethodProcessor. And it is registered two times, first time scanning only the arguments annotated with the @ModelAttribute, and the second time as a last in the list, resolving the arguments even if not annotated.

The list and the order of resolver you can check by checking the source of the RequestMappingHandlerAdapter. Note the two registrations of the ServletModelAttributeMethodProcessor, the true/false parameters determines if the annotation is mandatory or not

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 PathVariableMapMethodArgumentResolver()); resolvers.add(new MatrixVariableMethodArgumentResolver()); resolvers.add(new MatrixVariableMapMethodArgumentResolver()); 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; } 
Sign up to request clarification or add additional context in comments.

2 Comments

So the risk ... is that it can be matched by some other resolver - And which one might that be?
I'm not able to find the example, so I've removed it from the response
0

TLDR

When all you care is to populate an instance of your own type it doesn't matter.

Long version

In most cases it doesn't make a difference if you add @ModelAttribute or omit it. As @MasterSlave already mentioned the same mechanism is used behind the scenes. Before I talk about when it's important to use @ModelAttribute let me explain what the model actually is.

From the point of a view, that is being rendered, it's the data that can be accessed by the view. In your case the userDetail. The controller is responsible to add all necessary data to the model. There are many ways to achieve that. @ModelAttribute is one of them.

One use case for explicitly using @ModelAttribute is to define the key by which the data can be accessed. @ModelAttribute("user") UserDetail user let's the view access the data by the key user. Otherwise it would be userDetail.

The data may also already exist before the controller method is called. Maybe it's stored in the session or generated by another method. That's what is meant by

the argument should be retrieved from the model

But it may exist under a specific key, like "user". So again, you have to provide the name via @ModelAttribute("user"). The existing data could also be a "simple" type, like a String or a Date. In that case @ModelAttribute is necessary to retrieve the data from the model.

The same is true for arguments of types that would be handled by other resolvers, like Map or Locale.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.