diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java index c69d05545..b5c79bdfb 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java @@ -22,6 +22,8 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicReference; import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; import org.codehaus.jackson.map.ObjectMapper; import org.slf4j.Logger; @@ -1579,7 +1581,46 @@ public class RepositoryRestController Map m = new HashMap(); List errors = new ArrayList(); for(FieldError fe : ex.getErrors().getFieldErrors()) { - errors.add(fe.getDefaultMessage()); + String msg = applicationContext.getMessage(fe.getCode(), + new Object[]{fe.getObjectName(), fe.getField(), fe.getRejectedValue()}, + fe.getDefaultMessage(), + null); + errors.add(msg); + } + m.put("errors", errors); + + return negotiateResponse(request, HttpStatus.BAD_REQUEST, new HttpHeaders(), m); + } + + /** + * Send a 400 Bad Request in case of a validation failure. + * + * @param ex + * @param request + * + * @return + * + * @throws IOException + */ + @SuppressWarnings({"unchecked"}) + @ExceptionHandler(ConstraintViolationException.class) + @ResponseBody + public ResponseEntity handleJsr303ValidationFailure(ConstraintViolationException ex, + ServletServerHttpRequest request) throws IOException { + LOG.error(ex.getMessage(), ex); + + Map m = new HashMap(); + List errors = new ArrayList(); + for(ConstraintViolation cv : ex.getConstraintViolations()) { + String msg = applicationContext.getMessage(cv.getMessageTemplate(), + new Object[]{ + cv.getLeafBean().getClass().getSimpleName(), + cv.getPropertyPath().toString(), + cv.getInvalidValue() + }, + cv.getMessage(), + null); + errors.add(msg); } m.put("errors", errors); diff --git a/spring-data-rest-webmvc/src/test/groovy/org/springframework/data/rest/webmvc/spec/EventsSpec.groovy b/spring-data-rest-webmvc/src/test/groovy/org/springframework/data/rest/webmvc/spec/EventsSpec.groovy index 013fb477b..ce4f91141 100644 --- a/spring-data-rest-webmvc/src/test/groovy/org/springframework/data/rest/webmvc/spec/EventsSpec.groovy +++ b/spring-data-rest-webmvc/src/test/groovy/org/springframework/data/rest/webmvc/spec/EventsSpec.groovy @@ -2,10 +2,13 @@ package org.springframework.data.rest.webmvc.spec import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.rest.repository.RepositoryConstraintViolationException +import org.springframework.data.rest.test.webmvc.Customer import org.springframework.data.rest.test.webmvc.Person import org.springframework.data.rest.test.webmvc.TestRepositoryEventListener import org.springframework.http.HttpStatus +import javax.validation.ConstraintViolationException + /** * @author Jon Brisbin */ @@ -20,13 +23,37 @@ class EventsSpec extends BaseSpec { def request = createJsonRequest("POST", "people", null, person) when: - controller.create(request, baseUri, "people") + try { + controller.create(request, baseUri, "people") + } catch (RepositoryConstraintViolationException e) { + controller.handleValidationFailure(e, request) + throw e + } then: thrown(RepositoryConstraintViolationException) } + def "handles JSR-303 validation errors"() { + + given: + def cust = new Customer() + def request = createJsonRequest("POST", "customer", null, cust) + + when: + try { + controller.create(request, baseUri, "customer") + } catch (ConstraintViolationException e) { + controller.handleJsr303ValidationFailure(e, request) + throw e + } + + then: + thrown(ConstraintViolationException) + + } + def "captures before and after events"() { given: diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/ApplicationConfig.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/ApplicationConfig.java index 825effb46..ca14fd52b 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/ApplicationConfig.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/ApplicationConfig.java @@ -1,33 +1,14 @@ package org.springframework.data.rest.test; -import java.io.IOException; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.JsonGenerator; -import org.codehaus.jackson.Version; -import org.codehaus.jackson.map.Module; -import org.codehaus.jackson.map.SerializerProvider; -import org.codehaus.jackson.map.module.SimpleSerializers; -import org.codehaus.jackson.map.ser.std.SerializerBase; +import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.converter.Converter; +import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.data.rest.test.webmvc.Person; -import org.springframework.data.rest.test.webmvc.PersonValidator; -import org.springframework.data.rest.test.webmvc.TestRepositoryEventListener; -import org.springframework.format.support.DefaultFormattingConversionService; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.Resource; -import org.springframework.hateoas.ResourceProcessor; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.orm.jpa.JpaDialect; @@ -48,6 +29,12 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableTransactionManagement public class ApplicationConfig { + @Bean public MessageSource messageSource() { + ResourceBundleMessageSource ms = new ResourceBundleMessageSource(); + ms.setBasename("org.springframework.data.rest.test.ValidationErrors"); + return ms; + } + @Bean public DataSource dataSource() { EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.HSQL).build(); diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/Customer.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/Customer.java index 040c7bcbc..afc963597 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/Customer.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/Customer.java @@ -3,6 +3,7 @@ package org.springframework.data.rest.test.webmvc; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.validation.constraints.NotNull; /** * @author Jon Brisbin @@ -11,6 +12,7 @@ import javax.persistence.Id; public class Customer { @Id @GeneratedValue private Long id; + @NotNull private String userid; public Long getId() { diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/PersonValidator.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/PersonValidator.java index a452f1523..245b9511f 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/PersonValidator.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/test/webmvc/PersonValidator.java @@ -21,7 +21,7 @@ public class PersonValidator implements Validator { @Override public void validate(Object target, Errors errors) { Person p = (Person)target; LOG.debug(" ***** Validating Person " + p); - ValidationUtils.rejectIfEmpty(errors, "name", "field.name.required", "Field 'name' cannot be blank."); + ValidationUtils.rejectIfEmpty(errors, "name", "field.name.required"); } }