-
Notifications
You must be signed in to change notification settings - Fork 38.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@PathVariable and @ModelAttribute incompatibility prevent me from having a nice "update" handler [SPR-7608] #12264
Comments
Árpád Tamási commented I think it can be simply corrected here by dissolving annotation exclusivity and using the previously possibly created args[i] in modelattribute resolution: |
Árpád Tamási commented A proposed solution |
Rossen Stoyanchev commented Allowing two annotations won't solve the problem. For I would recommend using a @ModelAttribute
public void loadAccount(@PathVariable("account") Account acccount) That will work with both the show and the update methods both of which have an "account" path variable: @RequestMapping("show/{account}")
public String show(@PathVariable("account") Account account, Model model)
@RequestMapping(value = "update/{account}", method = { RequestMethod.PUT, RequestMethod.POST })
public String update(@Valid @ModelAttribute Account account, BindingResult bindingResult, Model model); Unfortunately that won't work well with the create method since its URL does not have the required path variable. Consider moving the create operation to a separate class. Or alternatively use |
Árpád Tamási commented My attached solution works well for months. You are right, the original resolveModelAttribute created a new object in the ways you explained but i created a fourth way, which uses the one parsed by if (boundedObject != null) {
bindObject = boundedObject;
} else ... |
Rossen Stoyanchev commented Yes I'm sure it can be made to work that way for some scenarios. My concern is about ambiguity. Given: public String update(@PathVariable("pk") Account account) { } To resolve the argument via |
Árpád Tamási commented I'm sure you're right about ambiguity. However, we would like to encapsulate all CRUD methods of an entity into a single controller. I just needed a quick solution that helps and my little patch does in the way we use it perfectly. @RequestMapping(value = "update/{account}", method = {RequestMethod.POST })
public String update(@PathVariable @Valid @ModelAttribute Account account, BindingResult bindingResult) {
// check bindingresult
...
try {
sAccount.update(account);
return new ModelAndView("redirect:name_of_details_view");
}
// handle exceptions
...
} However, I would gladly see an unambigous solution built into Spring that minimize update code without breaking our encapsulation rules. We love Spring and this problem is the only barrier it left in our way. |
Rossen Stoyanchev commented
I think there may be a way to resolve this cleanly with the new Note also that in 3.1 an |
Árpád Tamási commented
|
Rossen Stoyanchev commented
|
Árpád Tamási commented That's great but sometimes we do not need them in the returned model. Neither in the query string nor in JSTL expressions. Redirection was just an example of these cases. Anyway, it's not a big issue. |
Rossen Stoyanchev commented I've checked in the proposed solution. The approach is based on the
When created from a URI template variable, an attempt is made to locate and use a registered If you do give this a try, which would be great, please keep in mind you need to use the new RequestMappingHandlerMapping and RequestMappingHandlerAdapter. With the MVC namespace that will be the case, or otherwise just replace DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter with the above. |
Nicolas Romanetti opened SPR-7608 and commented
Spring MVC examples often refer to the creation of an entity using
@ModelAttribute
.A common pattern is to update an existing entity.
Generally you want to load the existing entity and then apply on it the allowed fields.
In my controller I have an handler for showing an entity, one for creating a new one...
here are their signature:
@RequestMapping
("show/{pk}")public String show(
@PathVariable
("pk") Account account, Model model)@RequestMapping
(value = "create", method = RequestMethod.POST)public String create(
@Valid
Account account, BindingResult bindingResult, Model model)Now, of course I need a handler, as nice as the one above to update the entity.
Here it is:
@RequestMapping
(value = "update/{pk}", method = { RequestMethod.PUT, RequestMethod.POST })public String update(
@Valid
@PathVariable
("pk") Account account, BindingResult bindingResult, Model model);The handler above is not accepted by SPring MVC, however I think it should! Here is what I would expect:
1/ convert the pk to the Account entity using the corresponding Parser (it works for "show" handler above...)
2/ Once converted, since the account is placed just before the bindingResult, it should be used to bind the request parameters that is to update directly the entity.
3/Once updated, it should perform the validation.
Note: I am confident in updating directly the entity as I know I can restrict the allowed fields thanks to an InitBinder.
The code above throw an exception:
org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public java.lang.String fr.nnn.web.controller.AccountController.update(fr.nnn.domain.Account,org.springframework.validation.BindingResult,java.lang.Boolean,java.lang.Boolean,org.springframework.ui.Model)]; nested exception is java.lang.IllegalStateException: Errors/BindingResult argument declared without preceding model attribute. Check your handler method signature!
I tried to add the
@ModelAttribute
("account") annotation after@PathVariable
("pk") but then another exception is thrown... stating that I cannot use both annotations at the same time.Am I missing something or do you agree it would be a nice feature?
Affects: 3.0.3
Attachments:
Issue Links:
@ModelAttribute
to play along with@RequestParam
/@RequestHeader
/...2 votes, 4 watchers
The text was updated successfully, but these errors were encountered: