Announcement Announcement Module
Collapse
No announcement yet.
Spring 3.1.0 @Valid JSON request + BindingResult = java.lang.IllegalStateException Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring 3.1.0 @Valid JSON request + BindingResult = java.lang.IllegalStateException

    My goal is to validate a JSON request. I am using Spring 3.1.0

    This was an issue but I thought was fixed in (3.1 M2) https://jira.springsource.org/browse/SPR-6709
    In the comments below, Rossen Stoyanchev says to make sure that you are using the latest stuff by "switching to the support classes" listed at http://static.springsource.org/sprin...1.html#d0e1515

    How do I make sure I am using the new support classes such as RequestMappingHandlerAdapter?

    To represent the JSON request, I have a Map<String, String> which works fine without validation. When I try to add validation, I get an
    Code:
    java.lang.IllegalStateException: Errors/BindingResult argument declared without preceding model attribute. Check your handler method signature!
    In my @Controller, I have a handler method and InitBinder that looks like this:

    Code:
    	@Autowired FooValidator fooValidator;
    
    	@RequestMapping(value="/somepath/foo", method=RequestMethod.POST)
    	public @ResponseBody Map<String, String> fooBar(
    			@Valid @RequestBody Map<String, String> specificRequest,
    			BindingResult results) {
    		
    		System.out.println("fooBar called");
    		
    		// get vin from JSON (reportRequest)
    		
    		return null;
    	}
    
    
    	@InitBinder("specificRequest") 
    	protected void initBinder(WebDataBinder binder){
    		binder.setValidator(fooValidator);
    	}

    My FooValidator looks like this:

    Code:
    @Component
    public class FooValidator  implements Validator {
    
    	public boolean supports(Class<?> clazz) {
    		out("supports called ");
    		return Map.class.equals(clazz);
    	}
    	
    	public void validate(Object target, Errors errors) {
    		out("validate called ");
    	}
    
    	
    	private void out(String msg) {
    		System.out.println("****** " + getClass().getName() + ": " + msg);
    	}
    }
    Thanks for your prompt assistance! (I hope to code this by Thursday (tomorrow)!)

  • #2
    Although it isn't obvious, the exception does point out correctly that the previous argument is not a model attribute. BindingResult is only supported with @ModelAttribute arguments. For @RequestBody arguments, validation errors are automatically translated into a 400 error by the DefaultHandlerExceptionResolver. You could catch MethodArgumentNotValidException, which contains the BindingResult and provide extra information in the response body if you like. The 3.1 documentation explains that.

    The rational is that with web service style methods where there is not need to select a view, so the processing can be fully automated and handled from a single place rather than in every controller method that has @RequestBody @Valid arguments. This is similar to how a BindingException is raised when BindingResult is not present after an @ModelAttribute argument.

    We can however improve the above error message to point out that BindingResult expects an @ModelAttribute argument. Feel free to open a ticket in JIRA.

    Comment

    Working...
    X