Announcement Announcement Module
Collapse
No announcement yet.
Validator, needing resource bundles for args to errors Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Validator, needing resource bundles for args to errors

    I have form labels and error messages in a resource bundle, like so:
    Code:
    error.required={0} is required
    label.firstname=First Name
    label.lastname=Last Name
    In the case of a validation error, I'd like to specify the 'error.required' message with a substitute arg of 'label.firstname' or 'label.lastname'. How is the best way to go about this? From what I've seen the args array in the ValidatorUtils only takes strings, not resource keys. Can I resolve these keys to i18n messages before placing them in the args array? If so, how?

    Thank you,
    Darin

  • #2
    Not sure if this is the best way, but you can use IoC to insert ResourceBundleMessageSource into our validator (or owning class) and use that to pull out the value for the key 'label.firstname'. It can then be substituted in when you retrieve the second message.

    Comment


    • #3
      I have the same question but I would like to know how to do it in JSP.
      Using the <sp:message /> can have args as a comma-delimited list. How can I pass another message as argument into the message?

      e.g.
      result.desc=The total amount is {0} {1}
      result.currency=USD

      I would like to have "The total Amount is USD 400", so how can I put the "USD" in another message?
      <spring:message code="result.desc" arguments="?,400" />

      Comment


      • #4
        I have checked that EL can be used inside the arugments attribute. But I'm not using JSP 2.0 so cannot directly insert the EL inside the attribute.

        Now if I want to do the message to message argument, I'm now using these ugly code:

        Resource
        Code:
        result.desc=The total amount is &#123;0&#125; &#123;1&#125;
        result.currency=USD
        JSP
        Code:
        <c&#58;set var="currency" scope="request">
            <spring&#58;message code="result.currency"/>
        </c&#58;set>
        <% String args= &#40;String&#41;request.getAttribute&#40;"currency"&#41; + ",400";%>
        <spring&#58;message code="result.desc" arguments="<%=args%>"/>
        result
        Code:
        The total amount is USD 400
        Any way to make it simpler?

        Comment


        • #5
          Originally posted by katentim
          Not sure if this is the best way, but you can use IoC to insert ResourceBundleMessageSource into our validator (or owning class) and use that to pull out the value for the key 'label.firstname'. It can then be substituted in when you retrieve the second message.
          I'm having the same problem as the OP. I'd independently come up with this idea, but the problem is that ResourceBundleMessageSource.getMessage() requires a Locale object and I have yet to find a method of getting the Locale of the user from within a Validator. I specifically do not want to use the default Locale that the application is running under.

          I thought about extending the whole validation framework in a way that I'd like it to work (given that it's not a lot of code), but important methods are declared as "final".

          Anyone got any further ideas? This is a very important omission from the framework IMO.

          Comment


          • #6
            OK, I solved my own problem - as usual had inspiration whilst posting...

            I add all form labels as arguments within the Validator like so:-

            Code:
            errors.rejectValue&#40;fieldName, "error.required", new Object&#123;"$&#123;login.field.username&#125;"&#125;, null&#41;;
            (Note the ${} around the field code)

            I then override onBindAndValidate in my Controller and resolve the parameters there.

            Code:
                protected void onBindAndValidate&#40;HttpServletRequest request, Object command, BindException errors&#41;
                    throws Exception 
                &#123;
                    // Resolve error arguments
                    if &#40;errors.hasErrors&#40;&#41;&#41;
                    &#123;
                        for &#40;Iterator iterator = errors.getAllErrors&#40;&#41;.iterator&#40;&#41;; iterator.hasNext&#40;&#41;;&#41;
                        &#123;
                            ObjectError nextError = &#40;ObjectError&#41;iterator.next&#40;&#41;;
                            Object&#91;&#93; arguments = nextError.getArguments&#40;&#41;;
                            
                            if &#40;arguments != null&#41;
                            &#123;
                                for &#40;int i = 0; i < arguments.length; i++&#41;
                                &#123;
                                    if &#40;arguments&#91;i&#93; instanceof String&#41;
                                    &#123;
                                        arguments&#91;i&#93; = resolveString&#40;&#40;String&#41;arguments&#91;i&#93;&#41;;
                                    &#125;
                                &#125;
                            &#125;
                        &#125;
                    &#125;
                &#125;
                
                private String resolveString&#40;String inputString&#41;
                &#123;
                    int startIndex = inputString.indexOf&#40;"$&#123;"&#41;;
                    
                    if &#40;startIndex == -1&#41;
                    &#123;
                        return &#40;inputString&#41;;
                    &#125;
                    
                    startIndex += 2;
                    
                    int endIndex = inputString.indexOf&#40;"&#125;", startIndex&#41;;
                    
                    if &#40;endIndex == -1&#41;
                    &#123;
                        return &#40;inputString&#41;;
                    &#125;
                    
                    try
                    &#123;
                        return &#40;getMessageSourceAccessor&#40;&#41;.getMessage&#40;inputString.substring&#40;startIndex, endIndex&#41;&#41;&#41;;
                    &#125;
                    catch &#40;Exception e&#41;
                    &#123;
                        log.error&#40;"Unable to resolve string - " + inputString, e&#41;;
                        
                        return &#40;inputString&#41;;
                    &#125;
                &#125;
            I've created an AbstractValidator and AbstractFormController that performs this functionality and all my Validators and Controllers now extends those classes.

            Hope that helps someone else...

            Bob

            Comment


            • #7
              Code:
              error.required=&#123;0&#125; is required
              label.firstname=First Name
              label.lastname=Last Name
              Here's what you can do :

              Code:
              errors.rejectValue&#40;"myfield", 
                "error.required", 
                 new Object&#91;&#93;&#123; new DefaultMessageSourceResolvable&#40;new String&#91;&#93;&#123;"label.firstname"&#125;&#41;&#125;,
                "first name is required."&#41;;
              Thanks to Seth for making me aware of this technique.

              Sanjiv

              Comment


              • #8
                Thanks Sanjiv. That looks like a much more elegant solution. Going to try it out now.

                This should really be in the docs somewhere. I couldn't find it at all, yet I'd assume it's a fairly common thing to want to do.

                Bob

                Comment


                • #9
                  I've added this to the Spring WIKI at least - http://opensource.atlassian.com/conf...ith+Spring+MVC

                  It's the Struts standard error messages link since that's what I'd have been looking for when I was searching for info on this.

                  Bob

                  Comment


                  • #10
                    Another suggestion is to inject the MessageSource object, as mentioned above, and create a MessageSourceAccessor as soon as it is inserted. Using it this way we solve the problem with the unknown default Locale also told in this thread.

                    I did something like this:

                    Code:
                    public void setMessageSource(MessageSource messageSource) {
                    	this.accessor = new MessageSourceAccessor(messageSource);
                    }
                    And then

                    Code:
                    ValidationUtils.rejectIfEmpty(errors, "category", "error.empty-field", new Object[] { accessor.getMessage("provider.data.category") }, "Value required.");
                    Does anyone see a problem with this solution?

                    Comment


                    • #11
                      Im using the same way , specified below in my ValidationUtil class:
                      Code:
                      errors.rejectValue("myfield", 
                        "error.required", 
                         new Object[]{ new DefaultMessageSourceResolvable(new String[]{"label.firstname"})},
                        "first name is required.");
                      In my jsp im using <spring:message code="${errMsgObj.code}" />
                      Here im getting null pointer exception.

                      Where is the resource bundle being loaded in web.xml or applciation context.

                      Comment


                      • #12
                        If i specify the above ways
                        errors.rejectValue(fieldKey, "errors.required", msgFormatArgs,
                        fallbackErrorMessage);

                        In jsp im getting the error msg as "errors.required" instead of the value specified for the key errors.required.

                        in jsp i used <spring:message code={}/>

                        Can anyone help me with this?

                        Comment

                        Working...
                        X