Problem:
I am trying to use as much Spring Boot Auto-configuration as possible to reduce boiler plate code. I cannot get the Spring Validation codes to automatically map to my externalized messages.properties. It will only work if I add my own LocalValidatorFactoryBean and use the fully qualified javax constraint message.
Goal
I want to override the defaultMessage for @javax.validation.constraints.NotNull globally in my application based on Spring Validation codes.
The first thing I did was register this bean...do I really have to? I see Spring Boot has one but it doesn't seem to correlate to messages.properties.
@Bean
public LocalValidatorFactoryBean validator(MessageSource messageSource) {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource);
return bean;
}
The next one is surprising to me. Spring Validation has this nifty DefaultMessageCodesResolver that provides excellent code strategy for failures that look something like this:
"code": "NotNull",
"codes": [
"NotNull.user.firstName",
"NotNull.firstName",
"NotNull.java.lang.String",
"NotNull"
],
But these codes aren't even considered for the @NotNull constraint. The spring documentation for Validation Conversion hints that something like this does exist but falls short of anything useful yet.
I wrote a sample application here and you can see that it's not working.
Question
How can I override the default message of Spring Validation errors based on those codes from messages.properties?
Relevant build.gradle
- springBootVersion = '2.0.0.RELEASE'
- compile('org.springframework.boot:spring-boot-starter-web')
src/main/resources/messages.properties:
NotNull.user.firstName=This doesn't work
NotNull.firstName=Or this
NotNull.java.lang.String=This doesn't work either
NotNull=And this doesn't work
javax.validation.constraints.NotNull.message=THIS DOES WORK! But why have codes then?
Spring Auto-Configuration Output proving the auto-config loaded.
MessageSourceAutoConfiguration matched:
- ResourceBundle found bundle URL [file:/home/szgaljic/git/jg-github/journey-through-spring/basic-web-validations/build/resources/main/messages.properties] (MessageSourceAutoConfiguration.ResourceBundleCondition)
- @ConditionalOnMissingBean (types: org.springframework.context.MessageSource; SearchStrategy: current) did not find any beans (OnBeanCondition)
Some other relevant start-up logs:
2018-03-26 14:32:22.970 TRACE 1093 --- [ main] o.s.beans.CachedIntrospectionResults : Found bean property 'validationMessageSource' of type [org.springframework.context.MessageSource]
Validation Constraint:
public class User {
@NotNull
private String username;
@NotNull
private String firstName;
}
Controller just for Testing:
@RestController
public class UserController {
@PostMapping("/users")
public List<ObjectError> testValidation(@Valid @RequestBody User user){
return null; // null implies no failed validations.. just for testing
}
}
Failed to use the codes
I tried to comment/uncomment the messages in messages.properties but it will only take the value of javax.validation.constraints.NotNull.message.
Because of the configuration
@Bean
public LocalValidatorFactoryBean validator(MessageSource messageSource) {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource);
return bean;
}
So you're using Bean Validation then spring get the messages from message.properties file that override from org.hibernate.validator.ValidationMessages.properties file using the key javax.validation.constraints.NotNull.message. If you would like to have key-value pairs:
NotNull.user.firstName=This doesn't work
NotNull.firstName=Or this
NotNull.java.lang.String=This doesn't work either
NotNull=And this doesn't work
to work you have to write as follows:
@Autowired
private MessageSource messageSource;
@PostMapping("/users")
public List<ObjectError> testValidation(@Valid @RequestBody User user, BindingResult bindingResult){
bindingResult.getFieldErrors().forEach(fieldError -> new ObjectError(
/*Assumes that ObjectError has constructor of ObjectError(String message) */
messageSource.getMessage(fieldError, Locale.getDefault())
));
return null;
}
来源:https://stackoverflow.com/questions/49499891/spring-boot-mapping-validation-codes-to-messagesource-message