views:

260

answers:

1

I've implemented a ReloadableResourceBundleMessageSource in my Spring MVC application which I use to display prettier error messages for binding exceptions. The problem I'm having is that, due to a company policy, these errors must be displayed in the following format:

[inputData] is not a valid [fieldName].

The field name is accessible by default in my message properties file (as the {0} argument), but I can't figure out a way to display the invalid user input. Is this possible?

A: 

Yes,

errors Tag does not allow you get the "value" supplied by your user - See link

Suppose here goes your errors.properties (root of the classpath) file (Notice i am using just one {0} argument)

// errors.properties

error.invalid=is not a valid {0}

When validating your command object, you do as follows

import static org.springframework.validation.ValidationUtils.*;

public boolean validate(Object command, Errors errors) {

    Person person = (Person) command;

    /**
      * new Object [] plays the role of the supplied arguments
      */
    rejectIfEmpty(errors, "age", "error.invalid", new Object[] {"Age"}, "Age is required");

    /**
      * If your label is a resource bundle key, use DefaultMessageSourceResolvable instead
      *
      * rejectIfEmpty(errors, "age", "error.invalid", new Object[] {new DefaultMessageSourceResolvable("person.age")}, "Age is required");
      */

}

UPDATE

But to get your goal, you must provide a custom messageSource (Notice implements instead of extends)

public class PolicyMessageSource implements MessageSource {

    private ResourceBundleMessageSource resourceBundle;

    public PolicyMessageSource() {
        resourceBundle = new ResourceBundleMessageSource();

        /**
          * Suppose your resource bundle is called messages.properties (root of the classpath)
          */
        resourceBundle.setBasenames(new String[] {"messages"});
    }

    public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
        return resourceBundle.getMessage(code, args, defaultMessage, locale);
    }

    public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
        return resourceBundle.getMessage(code, args, locale);
    }

    public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
        if(resolvable instanceof FieldError) {
            FieldError fieldError = (FieldError) resolvable;

            /**
              * Here goes what you want
              */
            return fieldError.getRejectedValue() + resourceBundle.getMessage(resolvable, locale);
        }

        return resourceBundle.getMessage(resolvable, locale);
    }

}

So define your PolicyMessageSource as messageSource

<bean id="messageSource" class="br.com.spring.PolicyMessageSource"/>

Be aware you must define just one messageSource instance called messageSource. Notice i am using ResourceBundleMessageSource instead. You must check out the same approach when using ReloadableResourceBundleMessageSource. Keep this in mind.

Arthur Ronald F D Garcia
Unfortunately it seems it is not possible to extend ResourceBundleMessageSource (or similarly ReloadableResourceBundleMessageSource) as you describe above. The reason being that the getMessage() methods in AbstractMessageSource are final.
TimmyJ
@TimmyJ ok, Timmy I will show how you can get your goal
Arthur Ronald F D Garcia
Worked great, thanks!
TimmyJ