views:

386

answers:

3

Hi all,

In a web application I'm working on using Spring 2.5.6.SEC01, I essentially have an Integer field that takes a number to determine which page to scroll to. The requirements changed, and we no longer want to display an error message, but simply ignore the user's input if they enter an invalid number, say "adfadf".

I was reading that you can do that via:

TypeMismatch.property=Some New Error Message

However, after having tried that, we are still getting the original error message: java.lang.Integer.TypeMismatch=...

I only want to disable this message for that given property. How can I do that? I still want binding to occur automatically, I just don't want to hear about it now.

Walter

A: 

You can register a custom PropertyEditor for that field, which wouldn't fail on type mismatch.

axtavt
I guess you're right, that isn't the solution I was looking for, but it will work. I'm holding out for a better solution, I would like to just flip a switch.
A: 

Since this is a Spring MVC application and assuming that it is a simple form, you can set this up in many ways. Can you specify your controller settings? For post request, you can record a suppressed field before the validator is called (assuming you have specified one) or after the validator is called. If you want to do it before validation, you can call [this][2]. After validation, you can call [this][3]

[2]: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html#onBind(javax.servlet.http.HttpServletRequest, java.lang.Object, org.springframework.validation.BindException) [3]: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html#onBindAndValidate(javax.servlet.http.HttpServletRequest, java.lang.Object, org.springframework.validation.BindException)

Kartik
Also, seems like another hack. This is too much of a hack to use.
A: 

According to DefaultMessageCodesResolver

In case of code "typeMismatch", object name "user", field "age"

  • typeMismatch.user.age
  • typeMismatch.age
  • typeMismatch.int
  • typeMismatch

So you should get (I suppose your commandName is called command and your property is age) Adapt according to your code

typeMismatch.command.age
typeMismatch.age
typeMismatch.java.lang.Integer
typeMismatch

Notice The third code

typeMismatch.java.lang.Integer

It will solve what you want

UPDATE

I have created a Person command class

public class Person implements Serializable {

    private Integer age;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

And a person controller

public class PersonController extends SimpleFormController {

    public PersonController() {
        setCommandClass(Person.class);
        setValidator(new Validator() {
            public boolean supports(Class clazz) {
                return clazz.isAssignableFrom(Person.class);
            }

            public void validate(Object command, Errors errors) {
                rejectIfEmpty(errors, "age", "Age is required");
            }
        });
    }

    @Override
    protected ModelAndView onSubmit(Object command) throws Exception {
        return new ModelAndView();
    }

}    

Here goes my myMessages.properties (root of the classpath)

typeMismatch.command.age=typeMismatch.command.age
typeMismatch.age=typeMismatch.age
typeMismatch.java.lang.Integer=typeMismatch.java.lang.Integer
typeMismatch=typeMismatch

So, i have done the following test

public class PersonControllerTest {

    private PersonController personController;
    private MockHttpServletRequest request;

    private MessageSource messageSource;

    @Before
    public void setUp() {
        request = new MockHttpServletRequest();
        request.setMethod("POST");

        personController = new PersonController();

        messageSource = new ResourceBundleMessageSource();
        ((ResourceBundleMessageSource) messageSource).setBasename("myMessages");
    }

    @Test
    public void failureSubmission() throws Exception {
        /**
         * Ops... a bindException
         * 
         * Age can not be a plain String, It must be a plain Integer
         */
        request.addParameter("age", "not a meaningful age");

        ModelAndView mav = personController.handleRequest(request, new MockHttpServletResponse());

        BindingResult bindException = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + "command");
        for (Object object : bindException.getAllErrors()) {
            if(object instanceof FieldError) {
                FieldError fieldError = (FieldError) object;

                assertEquals(fieldError.getField(), "age");

                /**
                  * outputs typeMismatch.command.age
                  */
                System.out.println(messageSource.getMessage((FieldError) object, null));
            }
        }
    }

}

If you want the second one, you must get rid of typeMismatch.command.age key resource bundle

typeMismatch.age=typeMismatch.age
typeMismatch.java.lang.Integer=typeMismatch.java.lang.Integer
typeMismatch=typeMismatch

Or write your own implementation of MessageCodesResolver

public class MyCustomMessageCodesResolver implements MessageCodesResolver {

    private DefaultMessageCodesResolver defaultMessageCodesResolver = new DefaultMessageCodesResolver();

    public String [] resolveMessageCodes(String errorCode, String objectName) {
        if(errorCode.equals("age"))
            /**
              * Set up your custom message right here
              */
            return new String[] {"typeMismatch.age"};

        return defaultMessageCodesResolver.resolveMessageCodes(String errorCode, String objectName);
    }

    public void String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType) {
        if(errorCode.equals("age"))
            /**
              * Set up your custom message right here
              */
            return new String[] {"typeMismatch.age"};

        return defaultMessageCodesResolver.resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType);
    }
}

And set up your PersonController

public class PersonController extends SimpleFormController {

    public PersonController() {
        setMessageCodesResolver(new MyCustomMessageCodesResolver());
        setCommandClass(Person.class);
        setValidator(new Validator() {
            public boolean supports(Class clazz) {
                return clazz.isAssignableFrom(Person.class);
            }

            public void validate(Object command, Errors errors) {
                rejectIfEmpty(errors, "age", "Age is required");
            }
        });
    }
Arthur Ronald F D Garcia
No, I don't want that to apply to all Integers. If anything, I'd want the the 2nd one:typeMismatch.ageI tried that with no success.
@Walter White Just for curiosity: do you have a messageSource instance *managed by Spring* <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basenames" value="YOUR MESSAGE SOURCE GOES HERE"/></bean> ?? It must be called **messageSource**
Arthur Ronald F D Garcia
yes, we have that configured.
@Walter White Updated
Arthur Ronald F D Garcia