Announcement Announcement Module
Collapse
No announcement yet.
How to customize JSR-303 Error Messages Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to customize JSR-303 Error Messages

    Hi,

    I am using validation using JSR-303 like this:

    @NotNull
    @Pattern(regexp=".+@.+\\.[a-z]+")
    protected String email;

    I want the error message "Email ID already exists" but what comes is "must match ".+@.+\.[a-z]+"

    Unable to find a way how to do this. Needing help.

  • #2
    try to set the message like this

    @Pattern(regexp=".+@.+\\.[a-z]+", message="my.message.key") and add in your messages.properties the same key and the translation

    Comment


    • #3
      c026 is correct, you need to add a message to your messages.properties file. You can specify the message key in the @Pattern annotation as suggested, or you can use the standard message keys supported by the DefaultMessageCodesResolver. In your case, if your class is named "Person" like this:

      Code:
      public class Person {
        @NotNull
        @Pattern(regexp=".+@.+\\.[a-z]+")
        protected String email;
      }
      Then you could add any of the following messages to your messages.properties file (where "person" and "email" are the name of the class and field in your code):

      Code:
      Pattern.person.email=Invalid e-mail address
      Pattern.email=Invalid e-mail address
      Pattern.java.lang.String=Invalid e-mail address
      Pattern=Invalid e-mail address
      Using this technique gives you lots of control over your messages. If you want each class that contains an "email" field to generate a different validation error message, then use the first form. If you want all "email" fields in all classes to give the same validation error message, then use the second form (field name without class name). As it is, you are getting the default message for the "Pattern=" message key.

      See http://static.springsource.org/sprin...sResolver.html for more detail.

      Comment


      • #4
        validation parameters

        Originally posted by scottyfred View Post
        c026 is correct, you need to add a message to your messages.properties file. You can specify the message key in the @Pattern annotation as suggested, or you can use the standard message keys supported by the DefaultMessageCodesResolver. In your case, if your class is named "Person" like this:

        Code:
        public class Person {
          @NotNull
          @Pattern(regexp=".+@.+\\.[a-z]+")
          protected String email;
        }
        Then you could add any of the following messages to your messages.properties file (where "person" and "email" are the name of the class and field in your code):

        Code:
        Pattern.person.email=Invalid e-mail address
        Pattern.email=Invalid e-mail address
        Pattern.java.lang.String=Invalid e-mail address
        Pattern=Invalid e-mail address
        Using this technique gives you lots of control over your messages. If you want each class that contains an "email" field to generate a different validation error message, then use the first form. If you want all "email" fields in all classes to give the same validation error message, then use the second form (field name without class name). As it is, you are getting the default message for the "Pattern=" message key.

        See http://static.springsource.org/sprin...sResolver.html for more detail.
        hi scotty,
        this is great but how can you send the annotation validation params to the message?

        for the @Size(min=3) i want to get the show the min value in the error message - something like Size.user.email=Minimum {1} characters

        Comment


        • #5
          I don't know for sure how to get the annotation variables into the message, but here is something to try:

          These are the default messages for several @Valid constraints:

          Code:
          javax.validation.constraints.Max.message=must be less than or equal to {value}
          javax.validation.constraints.Min.message=must be greater than or equal to {value}
          javax.validation.constraints.Pattern.message=must match "{regexp}"
          javax.validation.constraints.Size.message=size must be between {min} and {max}
          In these messages, the name of the annotation argument is included in the message using the {value} syntax. If you don't provide overrides to these in your messages.properties file, the {value} placeholder gets replaced with the annotation argument (as @skpatel20 showed in his original post with the @Pattern annotation).

          I don't know yet where this variable replacement in the default messages is getting done. I don't think it is by Spring, I think it is inside the validation framework. You can try using this syntax in your messages.properties file and see if the variable replacement gets done in that setup also (e.g. "Size.user.email=Minimum {min} characters").


          Scott

          Comment


          • #6
            Unfortunately, the suggestion in my previous post doesn't work. Here's why:

            The default validation messages with the named placeholders ({value}, {min}, {max}, etc.) are provided by and processed by the validation framework used by Spring to implement JSR-303 style annotation-driven validation. Hibernate Validator is the reference implementation and is most often used with Spring. The Hibernate Validator code has special-purpose message processing code that understands this type of placeholder. The validation framework also keeps a map of constraint information including the arguments to the annotation, and can look up placeholders like "value", "min", and "max" in this map.

            When you provide replacement messages in Spring's messages.properties file, these messages are processed by Spring's MessageSource mechanism. The default MessageSource mechanism uses java.text.MessageFormat. MessageFormat supports numeric placeholders ({0}, {1}, etc.).

            When a validation failure is detected, the validation framework returns several pieces of data back to the Spring DataBinder, including the arguments to the annotation. Unfortunately, inside of Spring's data binding and message resolution code these values are kept in a list so there is no good way to tell what each value means.

            So, I can't see a clean and safe way to get the annotation arguments to the output message. By observation, I can see that in the case of the @Size annotation the arguments passed to the MessageSource have the value of the "min" annotation arg in position 2 and the "max" value in position 4 of the list. So, using a message string like "Size.user.email=Minimum {2} and maximum {4} characters" yields the desired results. I suspect with single-argument annotations like @Min, @Max, @Pattern position 2 in the args list contains the annotation argument.

            I don't know if you can always rely on this placement in the args list. Unless that is part of the spec, other JSR-303 validator providers might build this list differently and future versions of the Hibernate provider might change the order.

            Seems like some solution to this would be a nice enhancement to Spring's JSR-303 validation support.

            Comment


            • #7
              Originally posted by scottyfred View Post
              Code:
              Pattern.person.email=Invalid e-mail address
              Pattern.email=Invalid e-mail address
              Pattern.java.lang.String=Invalid e-mail address
              Pattern=Invalid e-mail address
              Great!

              However, this

              Code:
              @Pattern(regexp=".+@.+\\.[a-z]+", message="my.message.key") and add in your messages.properties the same key and the translation
              worked but the message did not get translated.

              Comment


              • #8
                I filed a Jira issue for this: http://jira.springframework.org/browse/SPR-6730

                Comment


                • #9
                  What about this case?
                  I have a JodaTime dateTime type so I can use @DateTimeFormat

                  Code:
                      @NotNull @DateTimeFormat(pattern="dd/MM/yyyy")
                      @Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")
                      private DateTime dateOfBirth;
                  But if the date is entered in an incorrect format, I get this horrible validation message:

                  Failed to convert property value of type java.lang.String to required type org.joda.time.DateTime for property dateOfBirth; nested exception is org.springframework.core.convert.ConversionFailedE xception: Unable to convert value 2010-01-13 from type java.lang.String to type org.joda.time.DateTime; nested exception is org.springframework.core.convert.ConversionFailedE xception: Unable to convert value 2010-01-13 from type java.lang.String to type org.joda.time.DateTime; nested exception is java.lang.IllegalArgumentException: Invalid format: "2010-01-13" is malformed at "10-01-13"
                  because @DateTimeFormat doesn't support a message attribute, so something like
                  Code:
                  DateTimeFormat.dateOfBirth = The entered date is in an incorrect format.
                  doesn't work. Any ideas?

                  Comment


                  • #10
                    The @DateTimeFormat annotation is a formatter, not a validator, so it is not invoked in the same way that @NotNull and other validation annotations are invoked. It is used to parse the date, but does not validate that the date was entered in the correct format.

                    The validation error that gets thrown in this case is "typeMismatch", so you can set a property like this:

                    Code:
                    typeMismatch.dateOfBirth = The entered date is in an incorrect format.
                    An alternative solution would be to apply the @Pattern validation annotation to the date field with a regular expression that matches the date pattern you are looking for.

                    Comment


                    • #11
                      Hi,

                      in order to overwrite a message key you have to include the key in brackets, e.g.:
                      Code:
                      @AssertTrue(message = "{register.error.termsAccepted}")
                      protected boolean termsAccepted;
                      Without brackets you would overwrite the message, not the message key!
                      Within you message you can then use any of the placeholders the annotation defines, e.g. 'min' or 'max' of the size annoation.

                      At least this works for me using Spring 3 final and Hibernate Validator.

                      Comment


                      • #12
                        I am using my own tag to go trought all the error messages like this:

                        <c:forEach items="${errors.allErrors}" var="error">
                        <li><spring:message code="${error.code}" text="${error.code}"/></li>
                        </c:forEach>

                        However, this is not working right at all with my javax.validation anotations in my object class. I am only getting the constraint as error message, like with @NotEmpty the message shown is NotEmpty and so on.

                        I have tried to put the message on object class like:
                        @NotEmpty (message="You got an error here")

                        and codes:
                        @NotEmpty (message="{error.code}")

                        with defining the codes and translations in ValidatorMessages/messages.properties.

                        I have also tried forming the code like:

                        NotEmpty.myClass.MyProperty

                        but the result is always the same. To me it seems like the error code is different with javax. Can you help me with this please?

                        Comment


                        • #13
                          I assume you stored the Errors instance manually in the model using key 'errors'? You don't have to do that, the "Spring way" is to use Springs's errors tag, e.g.:

                          <form:form modelAttribute="...">
                          <form:errors path="" cssClass="error"/><%-- global errors --%>
                          <form:label for="firstname" path="firstname" cssErrorClass="error">firstname:</form:label>
                          <form:input path="firstname"/>
                          <form:errors path="firstname" cssClass="error"/>
                          ...
                          If you store the Errors instance by yourself try accessing it like this:
                          <spring:message message="${error}"/>
                          (because errors are MessageSourceResolvable)

                          or
                          <spring:message code="${error.code}" text="${error.defaultMessage}"/>
                          If you see the default message only the resolution of the validation resource does not work. The default is a resource called 'ValidatorMessages.properties'.

                          Comment


                          • #14
                            One more related question:

                            Is there any way to retrieve the "rejectedValue" attribute in the MessageSource properties file? I know how to retrieve the min, max, whatever values by index numbers, but the original value is not available but i need it within the message.

                            Something like:

                            Pattern.model.barcode=Submitted Order No. '{??}' is invalid.

                            ?? should be the "rejectedValue" attribute from my BindingResult of the specific error.

                            Any ideas? Thanks.

                            Marc

                            Comment

                            Working...
                            X