Wednesday, March 6, 2013

Custom internationalized error messages in Spring MVC + JSR303

A very common thing to do when building an application, is using JSR303 validation annotations on your domain classes. In a Spring MVC controller, those annotated fields will get validated when calling a ResuestMapping method with an @Valid parameter. You can then easily show the generated errors in your Spring MVC form.

So far so good. Only drawback is that Spring has some default messages. Which are clear, but usually not what you want in your frontend pages. Luckily, there's an easy way to override the defaults with custom messages!

NOTE: This small guide assumes you're using Spring MVC's Internationalization in a correct way, as described here

Ok, so overriding the messages. Actually, it's fairly easy. If you want to override each and every message for @NotEmpty, you add 1 entry to your file:

NotEmpty = This is the new default message for all NotEmpty annotations

Easy huh? Now if you want to be more specific, you can override the message for (for example) every firstname that is @NotEmpty:

NotEmpty.firstname = This is the new default message for NotEmpty annotations on firstname-fields

This will override the default message for every field named firstname. But you can even be more specific! You can define an error message for a specific field in a specific class. If you have an Employee class, with a firstname field that is annotated with @NotEmpty, you can specify a default message like this:

NotEmpty.employee.firstname = This is the new default message for the NotEmpty annotation on the firstname-field in our Employee class

There's one huge point of attention, though. The pattern of your message has to resemble the SPeL-pattern you'd use to access the field. Usually, the @Valid annotation will be on a command object. That means that in this case, our command object has to be named "employee" on the Model. If, however, you have named your command "command", you'll have to change the message key to this:

NotEmpty.command.firstname = This is the new default.

It's a pitfall, and one you can lose a lot of time with!