12

I'm a Spring newbie.

I set up validation in my domain class like this:

public class Worker {

    @NotNull(message="Name must be input")
    @Size(min=1,max=50, message="Name must not exceed 50 characters")
    private String name;
...

}

Here's the jsp file:

<form:input path="code" readonly="false" />
<font color="red"><form:errors path="code" />

And the controller code:

@RequestMapping(value="/test",method=RequestMethod.POST)
    public void form(@Valid Worker worker, BindingResult result) {

        if (result.hasErrors()) {
            return;
        }
...

It works, but how can I replace "Name must not exceed 50 characters" with some text (like worker.name.overflow) in my messageSource? May I need to add a messageResolver into BindingResult?

All the search result seems to say about writing a custom Validator class, but I want to use annotation for now. I'm pretty sure there's a way, because in this question someone has done that.

Community
  • 1
  • 1
Hoàng Long
  • 10,746
  • 20
  • 75
  • 124

2 Answers2

20

To tell Hibernate validator to do a lookup on a code, put the value of message in braces, e.g., @NotNull(message="{worker.name.NotNull}", then put the translation in ValidationMessages.properties in the root of your classpath (/WEB-INF/classes, resources folder in Maven, etc.).

The validator implementation looks those up independently on its own, and they go on the BindingResult already translated as the default message. Happens outside of the Spring messagesource. You could in theory override the LocalValidatorFactory bean to put the validator's message output onto the Errors object as the code and then leave the braces off in the annotation so that the Hibernate Validator passes it through. The source code that turns JSR-303 ConstraintViolations into Spring Errors is simple enough to read and extend. It just puts the name of the annotation on as code, the annotation properties as args, and then the validator's translation as the default message. You can read the implementation here.

You can add a javax.validation.MessageInterpolator to your javax.validation.Configuration to tell it to look for messages in other properties files. If you're using the Spring LocalValidatorFactory bean, it has a setMessageInterpolator() on it that you can use to inject one. Check this source for the Hiberate provider implementation.

Affe
  • 47,174
  • 11
  • 83
  • 83
  • I have done like your first paragraph: put a file name ValidationMessages.properties in WEB-INF, and add braces for the message, but it doesn't change. It seems the ValidationMessages.properties is not found. – Hoàng Long Apr 26 '11 at 07:11
  • sorry for my mistake, I have missed the part about putting ValidationMessages.properties in the class path. I would be very thankful if you can show me how to modify this default location? – Hoàng Long Apr 26 '11 at 07:36
  • Any way you can be more specific on changing the property file location? I'm using spring but your explanation sounds like Greek to me! – markthegrea Oct 05 '11 at 19:03
  • localValidatorFactoryBean.setMessageInterpolator(new ResourceBundleMessageInterpolator(new AggregateResourceBundleLocator(Arrays.asList("my.package.MyFileName", "my.other.package.AnotherFileName")))); – Affe Oct 05 '11 at 21:01
  • `LocalValidatorFactoryBean` has a `validationMessageSource` property which you can set a Spring `MessageSource` on, which is easier than setting up your own `MessageInterpolator`. – Nick Dec 07 '11 at 11:50
5

This is a bit explanation of problem.

@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.
Shan Arshad
  • 151
  • 1
  • 6