Spring WebMVC 3.2 and Validation
Spring 3.2 WebMVC has a neat new feature regarding validation and error handling. Let's say we have the following use case;
- objects are POSTed as JSON
- objects are @Valid on arrival
- any validation errors are returned as parsed JSON responses inside the body of the reply so that the client can process
so, first we have our normal request processor
package de.incompleteco.spring.web.controller;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import de.incompleteco.spring.web.domain.SimpleEntity;
@Controller
public class ValidatorController {
@RequestMapping(value="/simpleEntity",method=RequestMethod.POST)
public SimpleEntity process(@Valid SimpleEntity simpleEntity) throws Exception {
System.out.println("got it here");
simpleEntity.setProcessed("true");
return simpleEntity;
}
}
and here's the entity
package de.incompleteco.spring.web.domain;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
public class SimpleEntity implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull
private Long id;
private String processed;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProcessed() {
return processed;
}
public void setProcessed(String processed) {
this.processed = processed;
}
}
so if we pass it in without the id set, we'll get a BindingException.
with Spring 3.2 WebMVC, here's how we can catch
all the BindingExceptions across the application and return them. we want to return a 400 status code and the ObjectErrors in the body of the response.
package de.incompleteco.spring.web.controller;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import de.incompleteco.spring.web.domain.ErrorEntity;
@ControllerAdvice
public class ValidatorAdvice {
@ExceptionHandler(BindException.class)
public @ResponseBody ErrorEntity handleException(BindException exception,HttpServletResponse response) {
ErrorEntity entity = new ErrorEntity();
entity.setErrors(exception.getBindingResult().getAllErrors());
//set the response status
response.setStatus(HttpStatus.BAD_REQUEST.value());
//return
return entity;
}
}
and here's our "payload" entity
package de.incompleteco.spring.web.domain;
import java.io.Serializable;
import java.util.List;
import org.springframework.validation.ObjectError;
public class ErrorEntity implements Serializable {
private List< ObjectError > errors;
public List< ObjectError > getErrors() {
return errors;
}
public void setErrors(List< ObjectError > errors) {
this.errors = errors;
}
}
what our result will be is the ErrorEntity processed via Jackson (JSON) and the status code set to 400.
by the way, our Spring configuration is this;
don't ya love 3.2!