Search code examples
javaspringspring-mvcspring-roo

BindingResult rejectValue for Map field of form backing object


I have a Java class 'QueAndAns' which has one field

private Map<String,String> questionAndAnswerMap;

On my JSP page I have

<form:form  action="${submitURL}" method="POST" modelAttribute="queAndAns">  
    <c:forEach items="${queAndAns.questionAndAnswerMap}" var="questionAndAnswer"     varStatus="status">  
        <form:input     id="securityQuestions${status.index}" path="questionAndAnswerMap[${questionAndAnswer.key} ${questionAndAnswer.value}]"/>  
        <form:errors cssClass="errors" id="_securityQuestions_error_id" path="questionAndAnswerMap"/>            
    </c:forEach>  
    <input id="proceed" type="submit"  value="${fn:escapeXml(find_button)}"/>  
</form:form>

Now at my controller I want to see if user have answered all questions, else I want to return it with bindingResult.rejectValue. I'm trying something like this:

Map<String, String> questionAndAnswerMap = queAndAns.getQuestionAndAnswerMap();
    Iterator<Map.Entry<String, String>> iterator = questionAndAnswerMap.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, String> map = iterator.next();
        if (null == map.getValue() || StringUtils.isEmpty(map.getValue())) {
            bindingResult.rejectValue("questionAndAnswerMap" , "err_qna_not_blank", "Please fill up the answer for security questions");
        }
    }

but its not working.
Is there any way I can do it?


Solution

  • I've been struggling with this last few hours too. And finally found the solution:

    Your path definition should look like this

    <form:input id="securityQuestions${status.index}" path="questionAndAnswerMap['${questionAndAnswer.key}']"/>  
    <form:errors cssClass="errors" id="_securityQuestions_error_id" path="questionAndAnswerMap['${questionAndAnswer.key}']"/>
    

    And your validation should look like this

    bindingResult.rejectValue( "questionAndAnswerMap['"+map.getKey()+"']" , "err_qna_not_blank", "Please fill up the answer for security questions");
    

    I also tried to use 'nestedPath' tag and 'pushNestedPath()' method in a 'BindingResult' to make it more clean (without string concatenation) but it seems that it is not possible.