Skip to content
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

Allow Errors/BindingResult after @RequestBody [SPR-7114] #11774

Closed
spring-projects-issues opened this issue Apr 21, 2010 · 10 comments
Closed

Allow Errors/BindingResult after @RequestBody [SPR-7114] #11774

spring-projects-issues opened this issue Apr 21, 2010 · 10 comments
Assignees
Labels
has: votes-jira in: web type: enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Apr 21, 2010

Nick Padgett opened SPR-7114 and commented

Instead of using a command/form object, I bind much of my data to the request body. I expected that I could specify an Errors/BindingResult object after a @RequestBody method parameter. Currently, I do the following:

@RequestMapping(value = "/events", method = RequestMethod.POST)
public String create(@RequestBody final Event event,
        final HttpServletResponse response, final Model model)
        throws BindException {
    final BindingResult result = new BeanPropertyBindingResult(event, "");
    ValidationUtils.invokeValidator(this.eventValidator, event, result);
    if (result.hasErrors()) {
        throw new BindException(result);
    }
    ...
}

I would like to do the following:

@RequestMapping(value = "/events", method = RequestMethod.POST)
public String create(@RequestBody final Event event,
        final BindingResult result, final HttpServletResponse response,
        final Model model) throws BindException {
    ValidationUtils.invokeValidator(this.eventValidator, event, result);
    if (result.hasErrors()) {
        throw new BindException(result);
    }
    ...
}

However, when I do, I receive the following exception:

2010-04-21 09:48:09,014 [http-8080-2] WARN org.springframework.web.servlet.handler.SimpleMappingExceptionResolver  - Handler execution resulted in exception
org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public java.lang.String com.playonsports.event.controller.EventController.create(com.playonsports.event.bean.Event,org.springframework.validation.BindingResult,javax.servlet.http.HttpServletResponse,org.springframework.ui.Model) throws org.springframework.validation.BindException]; nested exception is java.lang.IllegalStateException: Errors/BindingResult argument declared without preceding model attribute. Check your handler method signature!
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:171)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:414)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:402)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
        ...
Caused by: java.lang.IllegalStateException: Errors/BindingResult argument declared without preceding model attribute. Check your handler method signature!
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:264)
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:163)
        ... 54 more

Affects: 3.0.2

Attachments:

11 votes, 13 watchers

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 24, 2010

Matt Goldspink commented

I'm also hitting this issue. Is it a bug that I can't do:

@Transactional
@RequestMapping(method=RequestMethod.POST, value="/add")
public Projects addNewProjects(@RequestBody @Valid Projects projects, BindingResult errors)

It would be nice to extend the validation to logic to other request data types (cookies, headers, request body) and not just model attribute. I can see use cases where I may store a cookie which stores JSON on the client side (to prevent multiple requests) and send it back to the server to be deserialised and validated. Stack trace below:

java.lang.IllegalStateException: Errors/BindingResult argument declared without preceding model attribute. Check your handler method signature!
	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:326)
	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:170)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:409)

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 24, 2010

Matt Goldspink commented

Ok after digging around a bit more I see a BindingResult object doesn't make sense because technically no data binding was done (at least not by Spring's data binding classes). Having said that if I change to an Errors object I don't see why the code couldn't be changed to allow the JSR 303 validator to be run over the result of the Jackson deserialization and passed into the method. I see in Keith's blog post here (http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/) he is doing the validation manually, but personally this seems like a feature Spring could do for me. I don't even care if I have to change Errors to be Set<ConstraintViolation<Projects>>, just some way for JSON and validation to happen out of the box would be fantastic.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 24, 2010

Matt Goldspink commented

Attaching my patched version of the HandlerMethodInvoker which seems to work for me (not the most ideal solution to the problem but for now it seems to work).

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jan 23, 2012

Guillaume Bilodeau commented

Sure would eliminate some boilerplate code to have this. Looking forward to it!

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Feb 23, 2012

Michel Zanini commented

Please resolve this issue. I can't make this work:

public Response post(@RequestBody @Valid Response response, BindingResult result) {

}

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Feb 24, 2012

Rossen Stoyanchev commented

This ticket was opened a while ago, so let me first mention that in Spring 3.1 we support @Valid on an @RequestBody argument. That seems to match the intent of the original request although not in exactly the same way as it was described then.

Neither BindingResult nor Errors are supported with @RequestBody arguments. If there are validation errors, a MethodArgumentNotValidExceptoin is thrown. This is captured by the DefaultHandlerExceptionResolver and converted to a 400 error code.

The rational is that with @RequestBody arguments we don't need to select a view and can handle the response automatically. Even if you wanted to change the default way of handling MethodArgumentNotValidException it would still be better to do so through @ExceptionHandler method for example.

@Michael, assuming you're using Spring 3.1 and have configured the new @MVC support classes (see what's new in Spring 3.1 in the reference docs and the chapter on configuring Spring MVC), then simply drop BindingResult and your example should work.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 10, 2012

Marc Logemann commented

I also hit this issue today and i must admit that i am also not happy with the way it works. For example we want to return a custom JSON error object back to the client dont want some kind of standard behavior. Furthermore the way spring operates should be content agnostic. This means from programming perspective it should not make a difference if we post url-formencoded to the backend (which is supported by BindingResult) or JSON. Spring should work the same.

Any feedback welcomed.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 21, 2012

Marc Logemann commented

solved sounds good but what version will have this included? Fix Version is still set to "none" in this ticket.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 21, 2012

Rossen Stoyanchev commented

Good catch. It's in master now and will be in the 3.2 M2 release at the end of this month.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 21, 2012

Jay Xu commented

Our proj use @ExceptionHandler to handle the exception, everything's OK

@spring-projects-issues spring-projects-issues added type: enhancement has: votes-jira in: web labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 3.2 M2 milestone Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has: votes-jira in: web type: enhancement
Projects
None yet
Development

No branches or pull requests

2 participants