How to use a custom message from my .properties file, but using the parameters provided by the @Size annotation?

sflr picture sflr · Nov 16, 2014 · Viewed 10.7k times · Source

That should be a simple problem but I couldn't find a straight forward solution.

I'm using the Spring Message Resource to provide all the texts on my system from a .properties file. I need that for internationalization questions and cannot use the default messages from the Spring.

Here is the problem:

I have the following line in my .properties file:

validator_invalid_state_name=Invalid name ({min}, {max})

The validation code is:

@Size( min=3, max=5, message="validator_invalid_state_name" )
public String name;

However, when an invalid value is sent to the field, the message is:

"Invalid name ({min}, {max})" and not "Invalid name (3, 5)".

I've tried several solutions without success, for example:

@Size( min=3, max=5, message="{validator_invalid_state_name}" )
@Size( min=3, max=5, message="${validator_invalid_state_name}" )
@Size( min=3, max=5, message="Size.name" ) // with "Size.name=Invalid name ({min}, {max})" in my .properties file
@Size( min=3, max=5, message="{Size.name}" ) //idem

But if I use only

@Size( min=3, max=5 )

Then, I get the default message from Spring (that I don't want to use). What I need is very simple: to use my own message from my custom .properties file, but using the parameters provided by the @Size annotation.

Any suggestions?

Thank you in advance.

Answer

Master Slave picture Master Slave · Nov 16, 2014

The proper syntax for accessing the key would be

@Size( min=3, max=5, message="{validator_invalid_state_name}" )

The problem however, is that in the default setup, the key lookup will not be done against your custom.properties, rather against Spring's ValidationMessages.properties. So the quickest way to get you up & running is to create a ValidationMessages.properties (and the 18n equivalents) and add your keys e.g.

validator_invalid_state_name=Invalid name ({min}, {max})

That's the simplest solution and no config headaches.

Now, since you would like this served from you properties file, well, its doable, but you'll have to find a proper configuration. For Spring 4.x, this would be the proper xml and java config.

Java Config

@Bean(name = "messageSource")
public MessageSource messageSource()
{
    ReloadableResourceBundleMessageSource bean = new ReloadableResourceBundleMessageSource();
    bean.setBasename("classpath:text");
    bean.setDefaultEncoding("UTF-8");
    return bean;
}

@Bean(name = "validator")
public LocalValidatorFactoryBean validator()
{
    LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
    bean.setValidationMessageSource(messageSource());
    return bean;
}

@Override
public Validator getValidator()
{
    return validator();
}

XML config

    <annotation-driven validator="validator">
    <!--i18n filtering-->
    <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <beans:property name="basenames">
            <beans:list>
                <beans:value>classpath:custom</beans:value>
            </beans:list>
        </beans:property>
        <beans:property name="defaultEncoding" value="UTF-8"/>
    </beans:bean>

  <beans:bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <beans:property name="validationMessageSource" ref="messageSource"/>
    </beans:bean>

For Spring mvc 3.x, you won't find the validationMessageSource property on the LocalValidatorFactoryBean, for that you will have to create you message interpolator, and set it up. You have an example in this thread http://forum.spring.io/forum/spring-projects/web/78675-jsr-303-validation-spring-mvc-and-messages-properties. Hope it helps