The orders of bean validation default parameters?
Asked Answered
H

3

9

I am currently trying to provide a custom validation message using bean validation.

Currently using spring mvc 3.1.1 + apache bean validation.

In my bean, i specify :

@Size(min=1, max=50)
private String title;

And in my messages.properties :

Size.addForm.title=The title must not be empty and must not exceed {1} characters.

From experiment, i found out that :

  • {0} refers to 'title'
  • {1} refers to the max, which is 50
  • {2} refers to the min, which is 1

and it'll be displayed as The title must not be empty and must not exceed 50 characters. which is correct.

But all these are from experiments. I wonder whether there are documentations stating the order of parameters for the default constraints ?

I tried hopefully using Size.addForm.title=The title must not be empty and must not exceed {max} characters. basing on the default ValidationMessages.properties but ends up with NumberFormatException on the {max}. I think it has something to do with the interpolations ?


Update

So, each of these fails independently with NumberFormatException on the {max} :

  • messages.properties : Size.addForm.title=The title must not be empty and must not exceed {max} characters.
  • messages.properties : Size=The title must not be empty and must not exceed {max} characters.
  • messages.properties : javax.validation.constraints.Size.message=The title must not be empty and must not exceed {max} characters.
  • ValidationMessages.properties : Size.addForm.title=The title must not be empty and must not exceed {max} characters.
  • ValidationMessages.properties : Size=The title must not be empty and must not exceed {max} characters.

This is the stacktrace :

java.lang.NumberFormatException: For input string: "max"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.text.MessageFormat.makeFormat(Unknown Source)
    at java.text.MessageFormat.applyPattern(Unknown Source)
    at java.text.MessageFormat.<init>(Unknown Source)
    at org.springframework.context.support.MessageSourceSupport.createMessageFormat(MessageSourceSupport.java:151)
    at org.springframework.context.support.ResourceBundleMessageSource.getMessageFormat(ResourceBundleMessageSource.java:281)
    at org.springframework.context.support.ResourceBundleMessageSource.resolveCode(ResourceBundleMessageSource.java:188)
    at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:205)
    at org.springframework.context.support.AbstractMessageSource.getMessage(AbstractMessageSource.java:146)
    at org.springframework.context.support.AbstractApplicationContext.getMessage(AbstractApplicationContext.java:1214)
    at org.springframework.web.servlet.support.RequestContext.getMessage(RequestContext.java:571)
    at org.springframework.web.servlet.support.BindStatus.initErrorMessages(BindStatus.java:177)
    at org.springframework.web.servlet.support.BindStatus.getErrorMessages(BindStatus.java:273)
    at org.springframework.web.servlet.tags.form.ErrorsTag.exposeAttributes(ErrorsTag.java:173)
    at org.springframework.web.servlet.tags.form.AbstractHtmlElementBodyTag.writeTagContent(AbstractHtmlElementBodyTag.java:48)
    at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102)
    at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)

This is the only one that works with the named parameter, it has to be ValidationMessages.properties, and it has to be exactly the key that exists in the default resource bundle by the jsr 303 implementation :

  • ValidationMessages.properties : javax.validation.constraints.Size.message=you know wad, the size must be between {min} and {max}

Basically the current conclusion is, by default, i cannot use named parameters on my specific messages. The named parameter only works when i override the exact key on the default jsr303 resourcebundle && when i use the same default jsr303 resourcebundle file name, which is ValidationMessages.properties

I prefer avoiding having to play with interpolation for now, hence the original question on how to find out that {0} or {1} or {2} refers to what in the documentation.

Hose answered 5/5, 2012 at 12:43 Comment(0)
C
4

JSR 303 Specification, 4.3.1.1. "Default message interpolation algorithm"

  • 4 - Message parameters are extracted from the message string. Those matching the name of an attribute of the constraint are replaced by the value of that attribute in the constraint declaration.

I read this like: you should use the name of the annotation properties for the message parameter, instead of numbers.

Appendix B "Standard ResourceBundle messages" of the specification shows some examples:

javax.validation.constraints.Min.message=must be greater than or equal to {value}
javax.validation.constraints.Max.message=must be less than or equal to {value}
javax.validation.constraints.Size.message=size must be between {min} and {max}
javax.validation.constraints.Digits.message=numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)

So it seems that named paramerter are the way you should use. (That {0}, {1} and {2} works too, seems to be a implementation "feature") - But in the end, this is only the behavior of the default message interpolator, the standard defines a way how to replace them by your own.


Update

The Hibernate Validation implementation seams to have an additional feature to format values ${validatedValue:<format>}. -- Maybe that helps you with your java.lang.NumberFormatException

@See Hibernate Validator Reference, Chapter 5.3. MessageInterpolator

Cartulary answered 5/5, 2012 at 17:49 Comment(1)
Thank you ! I 100% agree that the named parameters are the way to go, but it's quite bad news that {0} and friends is just an implementation feature, because the named parameters dont work well with me. I have updated my original post with the latest experiments.Hose
S
0

Better use:

    @Size(max=99)
    @NotBlank
    private String title;

since @Size allows whitespace characters, like space( ).

Samuelsamuela answered 5/4, 2016 at 12:42 Comment(0)
A
0
  • for Size.foo.bar interpolation with names doesn't work
  • however for size.foo.bar and baz.foo.bar it does (when validation annotation name isn't used; check is case sensitive)

Checked with message.properties file which is added in WebAppConfig extending WebMvcConfigurerAdapter like:

  @Bean
  public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasename("messages");
    return messageSource;
  }

  @Override
  public Validator getValidator() {
    LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
    bean.setValidationMessageSource(messageSource());
    return bean;
  }
Adaiha answered 27/9, 2017 at 14:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.