2

There is a grid which has multiple rows. Each row has the two same text fields. I am using JSR 303 to validate these fields and the validation is happening alright. However the issue is that multiple error messages are being shown(one for each row) which is not desirable. Is there a way to display only one error message per field for all the rows?

public ModelAndView insert(@Valid @ModelAttribute("proposalwiseselectionform")ProposalWiseSelectionForm proposalwiseselectionformobj,
                               BindingResult result,
                               HttpServletRequest request, HttpServletResponse response) {
        if (result.hasErrors()) {
            if (formBeanObj == null) {
                formBeanObj = proposalwiseselectionformobj;
            }
            mav = new ModelAndView("proposalwiseselection");

            mav.addObject("proposalwiseselectionform", formBeanObj);
        }
    }




public class ProposalWiseSelectionForm {
private String txtLineOfBusiness;
private String txtProduct;
private String btn;
private String clickedGo="N";   
private List arrLineOfBusiness=new ArrayList();
private List arrProduct=new ArrayList();
@Valid
private ArrayList documentList=initiateDocumentList();
private String txtPageMode="I";
private String enableDiscardBtn="N";
private String enableInsertBtn="N";

public ArrayList initiateDocumentList(){
    ArrayList arr=new ArrayList();
    for(int i=0; i<1;i++){
      arr.add(new ProposalWiseSelectionChildForm(i));
    }
    return arr;
  }
}



public class ProposalWiseSelectionChildForm {

private String numProposalWiseSelection;        
private String txtTransactionType;
private String txtTransactionTypeCode;  

@NotEmpty(message="Transaction Type cannot be empty")
private String txtTransactionDesc;

@NotEmpty(message="Document Type cannot be empty")
private String txtPolicyDocument;
private String ynChkBox="0";

}

JSP snippets are as follows,

form:form action="/proposalwiseselection" commandName="proposalwiseselectionform" method="POST" id="proposalwiseselection"/  
form:errors path="*" cssClass="errorblock" element="div"/
form:input path="documentList[${docStatus.index}].txtTransactionDesc"  cssClass="noneditableinputbox" size="40" onkeydown="transactionTypeLOV(event.keyCode,this)" readonly="true" title="Press F2 to get transaction type list" /
form:hidden path="documentList[${docStatus.index}].txtTransactionTypeCode"/
form:input path="documentList[${docStatus.index}].txtPolicyDocument"  cssClass="noneditableinputbox" size="40"  readonly="true"/
form:hidden path="documentList[${docStatus.index}].numPolicyDocumentCode"/
Shivayan
  • 136
  • 1
  • 2
  • 13

1 Answers1

0

Although the following solution is very crude, it however performs the functionality you need. You can easily work make a more readable and adhere to the Spring principals, but I just whipped this up to show how something like what you are asking can be done.

First of all you need to first obtain a Validator from Spring.

@Autowired
Validaror validator;

Next you need to remove the @Valid annotation and perform the validation on your own.

That means that your method would look like this:

public ModelAndView insert(@ModelAttribute("proposalwiseselectionform")ProposalWiseSelectionForm proposalwiseselectionformobj,
                               BindingResult result,
                               HttpServletRequest request, HttpServletResponse response)

{
        validate(bindingResult);
        if (result.hasErrors()) {
            if (formBeanObj == null) {
                formBeanObj = proposalwiseselectionformobj;
            }
            mav = new ModelAndView("proposalwiseselection");

            mav.addObject("proposalwiseselectionform", formBeanObj);
        }
}

Finally the validate method would look like this:

private void validate(BindingResult bindingResult) {

    final BindingResult intermediateBindingResult = new BeanPropertyBindingResult(bindingResult.getTarget(), bindingResult.getObjectName()) ;
    validator.validate(bindingResult.getTarget(), intermediateBindingResult);

    final List<FieldError> originalFieldErrors = intermediateBindingResult.getFieldErrors();
    final Set<String> alreadyAddedFieldNames = new HashSet<>();
    final List<FieldError> distinctFieldErrors = new ArrayList<>();
    for (FieldError fieldError : originalFieldErrors) {
        if(alreadyAddedFieldNames.contains(fieldError.getField())) {
            continue;
        }

        distinctFieldErrors.add(fieldError);
        alreadyAddedFieldNames.add(fieldError.getField());
    }

    for (FieldError distinctFieldError : distinctFieldErrors) {
        bindingResult.addError(distinctFieldError);
    }
}

What the code above does is store the regular validation into an intermediate binding result, and the loop over all the FieldError and adds only the first one per field.

geoand
  • 60,071
  • 24
  • 172
  • 190
  • Have i been able to project the problem precisely? do u need any more description? please ask if you want to know anything else.. – Shivayan May 22 '14 at 12:27
  • Here the fields are initialised in a list which is incremental for each row and is unique. So i believe the issue is that though the errors are same for each row each field error is treated as a separate entity. – Shivayan May 22 '14 at 12:57
  • Actually it seems like the answer is more complicated that what I posted, since the new BindingResult is completely ignored by Spring MVC – geoand May 22 '14 at 13:03
  • I am stuck here,please help me with the code.. "so I needed to autowire a simple Validator and then cast to SmartValidator". – Shivayan May 23 '14 at 07:19
  • You could simply use `@Autowired Validator validator` inside the class, and then inside the `validate` method you would need to first do `SmartValidator smartValidator = (SmartValidator) validator` before anything else. – geoand May 23 '14 at 07:25
  • Now i am getting the following exception...java.lang.ClassCastException: org.springframework.validation.beanvalidation.LocalValidatorFactoryBean cannot be cast to org.springframework.validation.SmartValidator – Shivayan May 23 '14 at 07:31
  • What version of Spring are you using? – geoand May 23 '14 at 07:37
  • You should be able to use the code without using `SmartValidator`, but with the simple `Validator`. Just forget about the `SmartValidator` and use `Validator` everywhere. I updated my answer – geoand May 23 '14 at 07:42
  • I really appreciate your time and effort but unfortunately the issue still persists.. – Shivayan May 23 '14 at 10:18
  • 4 errors, [Field error in object 'proposalwiseselectionform' on field 'docList[2].txtPolicyDocument':rejected value[null];default message[enter Doc Type], Field error in object 'proposalwiseselectionform' on field 'doc[3].txtTransactionDesc':rejected value[null];default message[enter Transaction Type], Field error in object 'proposalwiseselectionform' on field 'doc[2].txtTransactionDesc':rejected value[null];default message[enter Transaction Type], Field error in object 'proposalwiseselectionform' on field 'doc[3].txtPolicyDocument':rejected value[null];default message[enter Doc Type]] – Shivayan May 23 '14 at 10:58
  • As u can say the docList[i] is unique for every row as a result of which each the same field present in different rows is treated as a new one.. – Shivayan May 23 '14 at 11:00
  • Could you post your `ProposalWiseSelectionForm` to the question? – geoand May 23 '14 at 11:06
  • The reason my answer works for me and not for you is that you are using a validating a list – geoand May 23 '14 at 11:19
  • sorry i did not understand your point.. could you be more precise? – Shivayan May 23 '14 at 11:28
  • In general the solution I posted above works if you simple have multiple validation errors for a non collection field. It will only keep the first error for each field. In that respect, you could use it as a base and expand it to meet your owns need. You'll have to see which fields are needed and which not. One way to do that is using the debugger – geoand May 23 '14 at 11:32
  • @Shivayan No problem! I hope you resolve your issue! – geoand May 23 '14 at 11:39
  • I have somehow managed to do away with the multiple errors and return only the unique ones using bindingresult. So now when "result.hasErrors()" is executed after the binding result is returned from the Validate(), only the unique ones are shown. But even after this in the JSP as before multiple error messages are shown. any idea what could be the issue now? – Shivayan May 26 '14 at 07:42