11

I have the following situation. I have a validator to validate my command object and set the errors on a Errors object to be displayed in my form. The validator is invoked as expected and works okay, but the errors i set on the Errors objects are not displayed, when i am sent back to my form because of the validation errors.

Validator:

public void validate(Object obj, Errors err) {   
    MyCommand myCommand = (MyCommand) obj;   
    int index = 0;   
    for (Field field : myCommand.getFields()) {   
        if (field.isChecked()) {   
            if ((field.getValue() == null) || (field.getValue().equals(""))) {   
                err.rejectValue("fields[" + index + "].value", "errors.missing");   
            }   
        }   
        index++;   
    }   
    if (myCommand.getLimit() < 0) {   
        err.rejectValue("limit", "errors.invalid");   
    }   
}

Command:

public class MyCommand {   
    private List<Field> fields;   
    private int limit;   

    //getters and setters   
}   

public class Field {   
    private boolean checked;   
    private String name;   
    private String value;   

    //getters and setters   
}

Form:

    <form:form id="myForm" method="POST" action="${url}" commandName="myCommand">   
    <c:forEach items="${myCommand.fields}" var="field" varStatus="status">   
        <form:checkbox path="fields[${status.index}].checked" value="${field.checked}" />   
        <c:out value="${field.name}" />   
        <form:input path="fields[${status.index}].value" />   
        <form:errors path="fields[${status.index}].value" cssClass="error" /></td>   
        <form:hidden path="fields[${status.index}].name" />   
    </c:forEach>   
    <fmt:message key="label.limit" />    
    <form:input path="limit" />   
    <form:errors path="limit" cssClass="error" />   
</form:form>

Controller:

    @RequestMapping(value = REQ_MAPPING, method = RequestMethod.POST)   
    public String onSubmit(Model model, MyCommand myCommand, BindingResult result) {   
    // validate   
    myCommandValidator.validate(myCommand, result);   
    if (result.hasErrors()) {   
        model.addAttribute("myCommand", myCommand);   
        return VIEW;   
    }   

    // form is okay, do stuff and redirect   
}

Could it be that the paths i give in the validator and tag are not correct? The validator validates a command object containing a list of objects, so that's why i give a index on the list in the command object when registering an error message (for example: "fields["+index+"]".value). Or is it that the Errors object containing the errors is not available to my view?

Any help is welcome and appreciated, it might give me a hint or point me in right direction.

1
  • try to add <form:errors path="*" cssClass="error"/> in your form code to ensure your validator works ok Commented Mar 19, 2010 at 15:44

2 Answers 2

3

I found what is your problem. property fields in object myCommand always null. You need to create constructor for class MyCommand in which you need to use LazyList from Apache Commons or AutoPopulatingList from Spring to create auto growing list of Field

In example (using AutoPopulatingList):

public class MyCommand {   
    private List<Field> fields;   
    private int limit;   

    //getters and setters
    //...
    //Constructor
    public MyCommand() {
        fields = new AutoPopulatingList<Field>(Field.class);
    } 
}
Sign up to request clarification or add additional context in comments.

2 Comments

I finally got my form validation to work. As it turned out, Spring was adding the BindingResult object to the model, but under a different name (the classname beginning with lower case) than the command name I am using in my form tag. Changing the command name to reflect the name Spring is using to add the BindingResult to the model, got my form validation to work as expected. Anyway, thanks for you effort and help. ps. Why the need for LazyList? Because without it my form seems to work okay.
I agree with Yuri.Bulkin's answer. I faced the same problem before 2 months and I found this solution. You need to have LazyList initialization before you use the list of fields in the jsp using form tags of spring.
1

The line err.rejectValue("fields[" + index + "].value", "errors.missing"); will not do what you are trying to achieve. The first argument must be a property name of your Command bean, in your case fields.

To give the user a message you will have to use a parameterizable message in your properties file, eg. myform.field.error = you have an error in field {0}

So, use this method of the Errors object:

void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) 

Where you pass index into errorArgs

4 Comments

Thanks for your response mirror303. What I do not get precisely is what you mean with passing the index into errorArgs. I was under the assumption that errorArgs are arguments for the parameterized message in my properties file and have nothing to do with an indexed command property (like List). But probably I do not get what you're saying. So, do you mean that errorArgs should have the value "fields["+index+"].value"?
yes index, as in the method variable you use in the code you posted
But the index is an int and not an Object[] and fields[index].value is a String, so i do not see how using the index i can supply an Object[] as parameter.
You can create an array of java.lang.Integer objects (which will have only one element), and create an Integer object from the primitive int index that you have in your code. Now please vote up my answer :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.