diff --git a/spring-data-rest-example/src/main/java/org/springframework/data/rest/example/RestExporterExampleRestConfig.java b/spring-data-rest-example/src/main/java/org/springframework/data/rest/example/RestExporterExampleRestConfig.java index 7ed0ebcf2..dac711571 100644 --- a/spring-data-rest-example/src/main/java/org/springframework/data/rest/example/RestExporterExampleRestConfig.java +++ b/spring-data-rest-example/src/main/java/org/springframework/data/rest/example/RestExporterExampleRestConfig.java @@ -1,10 +1,13 @@ package org.springframework.data.rest.example; +import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.data.rest.config.RepositoryRestConfiguration; import org.springframework.data.rest.example.jpa.Person; +import org.springframework.data.rest.example.jpa.PersonValidator; import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; import org.springframework.hateoas.Link; import org.springframework.hateoas.Resource; @@ -17,6 +20,17 @@ import org.springframework.hateoas.ResourceProcessor; @ImportResource("classpath:META-INF/spring/security-config.xml") public class RestExporterExampleRestConfig extends RepositoryRestMvcConfiguration { + @Bean public MessageSource messageSource() { + ReloadableResourceBundleMessageSource msgsrc = new ReloadableResourceBundleMessageSource(); + msgsrc.setBasename("/WEB-INF/classes/ValidationMessages"); + msgsrc.setFallbackToSystemLocale(false); + return msgsrc; + } + + @Bean public PersonValidator beforeCreatePersonValidator() { + return new PersonValidator(); + } + @Override protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.addResourceMappingForDomainType(Person.class) .addResourceMappingFor("lastName") diff --git a/spring-data-rest-example/src/main/java/org/springframework/data/rest/example/jpa/PersonValidator.java b/spring-data-rest-example/src/main/java/org/springframework/data/rest/example/jpa/PersonValidator.java new file mode 100644 index 000000000..0dfb36594 --- /dev/null +++ b/spring-data-rest-example/src/main/java/org/springframework/data/rest/example/jpa/PersonValidator.java @@ -0,0 +1,21 @@ +package org.springframework.data.rest.example.jpa; + +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + +/** + * @author Jon Brisbin + */ +public class PersonValidator implements Validator { + + @Override public boolean supports(Class clazz) { + return Person.class.isAssignableFrom(clazz); + } + + @Override public void validate(Object target, Errors errors) { + ValidationUtils.rejectIfEmpty(errors, "firstName", "not.blank"); + ValidationUtils.rejectIfEmpty(errors, "lastName", "not.blank"); + } + +} diff --git a/spring-data-rest-example/src/main/resources/ValidationMessages_en_US.properties b/spring-data-rest-example/src/main/resources/ValidationMessages_en_US.properties new file mode 100644 index 000000000..0b32fad66 --- /dev/null +++ b/spring-data-rest-example/src/main/resources/ValidationMessages_en_US.properties @@ -0,0 +1 @@ +not.blank = Field {1} cannot be blank \ No newline at end of file diff --git a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/ValidationErrors.properties b/spring-data-rest-repository/src/test/resources/ValidationErrors.properties similarity index 100% rename from spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/ValidationErrors.properties rename to spring-data-rest-repository/src/test/resources/ValidationErrors.properties diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java index 29ce318f3..21533830a 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java @@ -8,6 +8,7 @@ import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import javax.validation.ConstraintViolationException; import org.slf4j.Logger; @@ -140,9 +141,10 @@ public class AbstractRepositoryRestController implements ApplicationContextAware ConstraintViolationException.class }) @ResponseBody - public ResponseEntity handleConstraintViolationException(ConstraintViolationException cve) { + public ResponseEntity handleConstraintViolationException(Locale locale, + ConstraintViolationException cve) { return response(null, - new ConstraintViolationExceptionMessage(cve, applicationContext), + new ConstraintViolationExceptionMessage(cve, applicationContext, locale), HttpStatus.BAD_REQUEST); } @@ -150,9 +152,10 @@ public class AbstractRepositoryRestController implements ApplicationContextAware RepositoryConstraintViolationException.class }) @ResponseBody - public ResponseEntity handleRepositoryConstraintViolationException(RepositoryConstraintViolationException rcve) { + public ResponseEntity handleRepositoryConstraintViolationException(Locale locale, + RepositoryConstraintViolationException rcve) { return response(null, - new RepositoryConstraintViolationExceptionMessage(rcve, applicationContext), + new RepositoryConstraintViolationExceptionMessage(rcve, applicationContext, locale), HttpStatus.BAD_REQUEST); } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationExceptionMessage.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationExceptionMessage.java index eeb878414..788740abe 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationExceptionMessage.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationExceptionMessage.java @@ -2,6 +2,7 @@ package org.springframework.data.rest.webmvc.support; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; @@ -16,10 +17,12 @@ public class ConstraintViolationExceptionMessage { private final ConstraintViolationException cve; private final List messages = new ArrayList(); - public ConstraintViolationExceptionMessage(ConstraintViolationException cve, MessageSource msgSrc) { + public ConstraintViolationExceptionMessage(ConstraintViolationException cve, + MessageSource msgSrc, + Locale locale) { this.cve = cve; for(ConstraintViolation cv : cve.getConstraintViolations()) { - messages.add(new ConstraintViolationMessage(cv, msgSrc)); + messages.add(new ConstraintViolationMessage(cv, msgSrc, locale)); } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationMessage.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationMessage.java index 09ce984e1..d80038854 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationMessage.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ConstraintViolationMessage.java @@ -2,6 +2,7 @@ package org.springframework.data.rest.webmvc.support; import static java.lang.String.*; +import java.util.Locale; import javax.validation.ConstraintViolation; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,39 +15,41 @@ import org.springframework.context.MessageSource; */ public class ConstraintViolationMessage { - private final ConstraintViolation violation; - private final String message; + private final ConstraintViolation violation; + private final String message; - public ConstraintViolationMessage(ConstraintViolation violation, MessageSource msgSrc) { - this.violation = violation; - this.message = msgSrc.getMessage(violation.getMessageTemplate(), - new Object[]{ - violation.getLeafBean().getClass().getSimpleName(), - violation.getPropertyPath().toString(), - violation.getInvalidValue() - }, - violation.getMessage(), - null); - } + public ConstraintViolationMessage(ConstraintViolation violation, + MessageSource msgSrc, + Locale locale) { + this.violation = violation; + this.message = msgSrc.getMessage(violation.getMessageTemplate(), + new Object[]{ + violation.getLeafBean().getClass().getSimpleName(), + violation.getPropertyPath().toString(), + violation.getInvalidValue() + }, + violation.getMessage(), + locale); + } - @JsonProperty("entity") - public String getEntity() { - return violation.getRootBean().getClass().getName(); - } + @JsonProperty("entity") + public String getEntity() { + return violation.getRootBean().getClass().getName(); + } - @JsonProperty("message") - public String getMessage() { - return message; - } + @JsonProperty("message") + public String getMessage() { + return message; + } - @JsonProperty("invalidValue") - public String getInvalidValue() { - return format("%s", violation.getInvalidValue()); - } + @JsonProperty("invalidValue") + public String getInvalidValue() { + return format("%s", violation.getInvalidValue()); + } - @JsonProperty("property") - public String getProperty() { - return violation.getPropertyPath().toString(); - } + @JsonProperty("property") + public String getProperty() { + return violation.getPropertyPath().toString(); + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java index ca854d63b..4d65f4cb7 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java @@ -2,6 +2,7 @@ package org.springframework.data.rest.webmvc.support; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import com.fasterxml.jackson.annotation.JsonProperty; import org.springframework.context.MessageSource; @@ -13,35 +14,69 @@ import org.springframework.validation.FieldError; */ public class RepositoryConstraintViolationExceptionMessage { - private final RepositoryConstraintViolationException violationException; - private final List errors = new ArrayList(); + private final RepositoryConstraintViolationException violationException; + private final List errors = new ArrayList(); - public RepositoryConstraintViolationExceptionMessage(RepositoryConstraintViolationException violationException, - MessageSource msgSrc) { - this.violationException = violationException; + public RepositoryConstraintViolationExceptionMessage(RepositoryConstraintViolationException violationException, + MessageSource msgSrc, + Locale locale) { + this.violationException = violationException; - for(FieldError fe : violationException.getErrors().getFieldErrors()) { - List args = new ArrayList(); - args.add(fe.getObjectName()); - args.add(fe.getField()); - args.add(fe.getRejectedValue()); - if(null != fe.getArguments()) { - for(Object o : fe.getArguments()) { - args.add(o); - } - } + for(FieldError fe : violationException.getErrors().getFieldErrors()) { + List args = new ArrayList(); + args.add(fe.getObjectName()); + args.add(fe.getField()); + args.add(fe.getRejectedValue()); + if(null != fe.getArguments()) { + for(Object o : fe.getArguments()) { + args.add(o); + } + } - String msg = msgSrc.getMessage(fe.getCode(), - args.toArray(), - fe.getDefaultMessage(), - null); - this.errors.add(msg); - } - } + String msg = msgSrc.getMessage(fe.getCode(), + args.toArray(), + fe.getDefaultMessage(), + locale); + this.errors.add(new ValidationError(fe.getObjectName(), + msg, + String.format("%s", fe.getRejectedValue()), + fe.getField())); + } + } - @JsonProperty("errors") - public List getErrors() { - return errors; - } + @JsonProperty("errors") + public List getErrors() { + return errors; + } + + public static class ValidationError { + String entity; + String message; + String invalidValue; + String property; + + public ValidationError(String entity, String message, String invalidValue, String property) { + this.entity = entity; + this.message = message; + this.invalidValue = invalidValue; + this.property = property; + } + + public String getEntity() { + return entity; + } + + public String getMessage() { + return message; + } + + public String getInvalidValue() { + return invalidValue; + } + + public String getProperty() { + return property; + } + } }