Spring MVC + Hibernate validator : how can I override/internationalize the default error messages? - spring

I'm working on a Spring MVC project in which I'm using Hibernate Validator to validate input fields from a form. As my project is Maven-based, I added this dependency:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>4.1.0.Final</version>
</dependency>
The form validation process works fine but now, I would like to override or internationalize the default error messages.
For instance, by default, using the #NotEmpty annotation will yield the message "may not be empty". How I can replace this message by my own message? I've tried several solutions:
defining a Spring bean with id "messageSource" and setting its "basenames" property
creating ValidationMessages.properties file in the project classpath
But the default messages are still displayed...
Any hint?
Thx in advance.

Yes you can do that. You can load the error message from the properties files. But you need to have the key in a proper format. Like NotEmpty.ClassName.fieldName=fieldName Can not be empty.
You just need to specify your exact class name and property name in your properties files. Everything other is looking just perfect in your case.
You can also have a common error message for a particular type of validation annotation for all the fields having that annotation. Like javax.validation.constraints.NotNull=Notnull erro happened!
Hope this helps you. Cheers.

This is a bit explanation that how you can find the exact property name behind every annotation given or used for validation. See below mentioned steps.
#Size(min = 1, max = 50, message = "Email size should be between 1 and 50")
Now remove { message = "Email size should be between 1 and 50" } from validation tag.
After doing this your annotation will be like this.
#Size(min = 1, max = 50)
Now at controller side debug the method which is being called upon when submitting the form. Below is my method which is receiving the request when user hits submit.
public static ModelAndView processCustomerLoginRequest(IUserService userService,LoginForm loginForm,
HttpServletRequest request, HttpSession session, BindingResult result, String viewType, Map<String, LoginForm> model)
Now place a debug point at very first line of the method and debug the argument "result".
BindingResult result
While dubugging you will find a string like this in codes array.
Size.loginForm.loginId
Now define this string in your properties file and a message against that string. Compile and execute. That message will be displayed whenever that annotation wouldn't be validated.
Size.loginForm.loginId=email shouldn't be empty.
Basically spring makes its own string as key to its property file message. In above key
Size(#Size) = validation annotation name
loginForm = My Class Name
loginId = Property name in LoginForm class.
The Beauty of this method is it also runs fine while you will be using Spring Internationalization. It automatically switches the messages file as language changes.

Related

This annotation is not allowed at this location (#Valid)

I am trying to validate the list which is passed as a parameter to a controller in spring-boot application.
I referred Baeldung doc to perform the same, below is the code snippet which i tried to implement
#PostMapping
public void addAll(#RequestBody #NotEmpty(message = "Input movie list cannot be empty.") List<#Valid Movie> movies) {
movieService.addAll(movies);
}
but it throws an error saying "#Valid annotation is not allowed in this location" (this is compile time error, i haven't executed the code hence there is no stacktrace)
Suggest a fix for the same
I did the same thing as shown in the image
make sure the #Valid annotaion is in front of the List and not the generic list type.
Also make sure your Movie class implements #Valid validations.

javax.validation.constraints.#Max not working as request param

Tried to add #Max validation for the sizes request parameter. However, it seems whatever value I put in will be valid.
A simple controller method in a spring boot application.
#GetMapping("/all")
public String getAll(#RequestParam #Max(value=20, message = "should be less than 20") int sizes) {
if (sizes > 20) {
return "Pass but not valid";
}
return "Valid";
}
when request param sizes is 21, I get Pass but not valid rather error message
http://localhost:8080/all?sizes=21
Any advice? Thanks
dit you put #Validated above you class?
I found the following answer (Spring Controller: RequestParam not validated despite #Valid and #Size) helpful for exactly this question.
Basically, it says that:
MethodValidationPostProcessor needs to be added to a configuration.
#Validated annotation needs to be added on top of the controller class.
Possibly some exceptions like ConstraintViolationException or MethodArgumentNotValidException will need to be handled if customized responses are wanted.
For this setup to run, I had to add spring-boot-starter-validation like it's said in this answer: "The Bean Validation API is on the classpath but no implementation could be found" preventing startup

Spring annotation for making two fields mandatory out of four data fields

I have four data fields and i have to make sure that i receive data for at least two fields out of four. I am using spring 3 mvc and i wanted to know that if we have any annotation availabe in spring which can be used to group this not null logic across four fields.
Yes, You can do it by annotation #NotEmpty of Hibernate Validator it will check value to be not null and size is > 0
This annotation is given on fields of bean for which you need to make it required fields.
On client side if your are using Spring form tag than there is attribute modelattribute=BeanName which map your form fields to Bean fields.
On controller side you need to validate this bean before proceed it further, for this you need to include #valid annotation before your bean object argument in controller as show below
public String submitForm(#Valid MyBean myBean, BindingResult result, Model m)
{
if(result.hasErrors()) {
return "formPage"; //return to error page or display error on client side
}
m.addAttribute("message", "Successfully saved form: ");
return "formPage";
}
result.hasErrors() return true if fields value in invalid as per validation define in your bean class. It return false if all values are correct.
Here is complete example on Validate Form fields in Spring MVC.
This can be achieved by simply creating a custom validator annotation in spring

Spring-MVC bean Validation Type mismtach error

I am trying to validate an object using Spring JSR303 validation, i have a form object which have some nested objects along with some form properties here is my Form signature
public class PaymentDetailsForm
{
private AddressForm billingAddress;
// other properties and getter and setters
}
In my AddressForm bean i have used Bean validation annotations to validate data, but i am not using any #Valid annotation inside my PaymentDetailsForm for billingAddress.
This is the signature of my Controller method
public String createUpdatePaymentInfos(final Model model,
#ModelAttribute("paymentInfo") #Valid final PaymentDetailsForm form, final BindingResult bindingResult)
{
}
If i am sending correct data from the form everything is working perfectly fine, but if i omit any field from billingAddress which is marked as required or not null i am getting following binding error exception
org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'paymentInfo' on field 'billingAddress':
rejected value [com.xxx.storefront.forms.AddressForm#e39f6f1,true];
codes [typeMismatch.paymentInfo.billingAddress,typeMismatch.billingAddress,typeMismatch.com.xxx.storefront.forms.AddressForm,typeMismatch];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable:
codes [paymentInfo.billingAddress,billingAddress]; arguments []; default message [billingAddress]];
default message [Failed to convert property value of type 'java.lang.String[]'
to required type 'com.xxx.storefront.forms.AddressForm' for property 'billingAddress';
nested exception is java.lang.IllegalStateException:
Cannot convert value of type [java.lang.String[]] to required type [com.xxx.storefront.forms.AddressForm] for property 'billingAddress':
no matching editors or conversion strategy found]
I was expecting that since i have not used #valid annotation for billingAddress property, it should not be validated but even in case it get validated i am not able to understand above mentioned exception/error
The bindingResult that you are seeing doesn't look like it is because of validation errors, it is likely because of the binding errors - not being able to bind the UI fields to the inner billingAddress field. Even the binding errors would end up showing in the immediately following bindingresult argument like you are seeing.
That was due to some wrong mapping from UI,in my JSP page i was mapping address fields to billingAddress object but there was one hidden field like
<form:hidden path="billingAddress" id="billingAddress"/>
This was the cause of error since it was trying to send String array and Spring binding was unable to distinguish what i am trying to do

spring mvc annotation validation integer

I have an object.
public class MyObject
{
....
#Column(name = "a_number") #NotNull #NumberFormat(style = Style.NUMBER) #Min(1)
private Integer aNumber;
...
//getters and setters
}
In my controller I have #Valid annotation on my object being posted. I do have validation working on all my other fields in the class (their all Strings) except this number. If I enter a number from my form it works fine and if I violate the #Min(1) it also gives me the correct validation error. My problem however is that if you enter a string instead of a number it throw a NumberFormatException.
I've seen many examples of Integer and validation but no one accounts for if you enter a string into the form being posted. Do I need to do the validation else where? Javascript? I would like a solution that falls in line with the rest of spring validation so I could use this in other classes. I would just like an error stating it must be numeric. Also I tried using the #Pattern annotation but apparently thats just for strings.
Suggestions?
You can add the following to your file which controls your error messages (these are the generic ones it looks for in the case of a type mismatch:
typeMismatch.commandObjectName.aNumber=You have entered an invalid number for ...
typeMismatch.aNumber=You have entered an invalid number for ...
typeMismatch.java.lang.Integer=You have input a non-numeric value into a field expecting a number...
typeMismatch=You have entered incorrect data on this page. Please fix (Catches all not found)
For those who did not get the idea right here is what to do in spring 4.2.0.
Create a file name messages.properties in WEB-INF > classes folder. And put the above type mismatch messages in that file.
In spring configuration or servlet.xml file create the following bean.
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="messages"></beans:property>
</beans:bean>
And for your model attribute like private Integer aNumber; in the question along with other validation rules this rule is also applied for type mismatch conversion. You will get your desired message in this.
<form:errors path="aNumber"></form:errors>
Hope it helps others.
Still relevant, so I'll add the programmatical approach of message source bean definition:
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}

Resources