Home > front end >  Validate List<Object> using Spring validator
Validate List<Object> using Spring validator

Time:01-08

Question: how to set proper nested path for Errors for List target in validator to invoke other validator ?

Code reference: nested spring validator for nested object

public class AllergyDtoListValidator implements Validator {

  private AllergyDtoValidator allergyDtoValidator;

  @Override
  public boolean supports(Class<?> clazz) {
    return new TypeToken<List<AllergyDto>>() {
    }.getType().equals(clazz);
  }

  @Override
  public void validate(Object target, Errors errors) {
    allergyDtoValidator = new AllergyDtoValidator();
    List<AllergyDto> request = (List<AllergyDto>) target;
    for (int i = 0; i < request.size(); i  ) {
      // below line causes the exception
      errors.pushNestedPath(String.valueOf(i));
      ValidationUtils.invokeValidator(this.allergyDtoValidator, request.get(i), errors);
      errors.popNestedPath();
    }
  }
}

public class AllergyDtoValidator implements Validator {

  @Override
  public boolean supports(Class<?> clazz) {
    return AllergyDto.class.isAssignableFrom(clazz);
  }

  @Override
  public void validate(Object target, Errors errors) {

    AllergyDto request = (AllergyDto) target;
    log.info("Enter allergy validator {}", request.toString());
    try {
      // field allergyTypeCode
      if (request.getAllergyTypeCode() == null || request.getAllergyTypeCode().isEmpty()) {
        errors.rejectValue("allergyTypeCode", "Cannot be null nor whitespace");
      } else if (request.getAllergyTypeCode().length() > 8) {
        errors.rejectValue("allergyTypeCode", "Exceed max length");
      }
      // field allergyCode
      ValidationUtils.rejectIfEmptyOrWhitespace(errors, "allergyCode", "Cannot be null nor "
            "whitespace");
      if (request.getAllergyCode() != null && request.getAllergyCode().length() > 8) {
        errors.rejectValue("allergyCode", "Exceed max length");
      }
      // field allergyName
      if (request.getAllergyName() != null && request.getAllergyName().length() > 66) {
        errors.rejectValue("allergyName", "Exceed max length");
      }
      // field remarks
      ValidationUtils.rejectIfEmptyOrWhitespace(errors, "remarks", "Cannot be null nor whitespace");
      if (request.getRemarks() != null && request.getRemarks().length() > 255) {
        errors.rejectValue("remarks", "Exceed max length");
      }
    } catch (Exception e) {
      log.info("Exception {}", e);
    }
    log.info("allergy errors {}", errors.toString());

  }

}

public class AllergyDto implements Serializable {
  private static final long serialVersionUID = 2319040437020676767L;
  @JsonProperty("allergy_type_code")
  private String allergyTypeCode;
  @JsonProperty("allergy_code")
  private String allergyCode;
  @JsonProperty("allergy_name")
  private String allergyName;
  @JsonProperty("remarks")
  private String remarks;
  // getters and setters

}

when I run

// req is List<AllergyDto>
allergyDtoListValidator.validate(req, bindingResult);

I got exception

org.springframework.beans.NotReadablePropertyException: Invalid property '0' of bean class [java.util.ArrayList]: Bean property '0' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:627) at org.springframework.beans.AbstractNestablePropertyAccessor.getNestedPropertyAccessor(AbstractNestablePropertyAccessor.java:843) at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyAccessorForPropertyPath(AbstractNestablePropertyAccessor.java:820) at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:615) at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:104) at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:228) at org.springframework.validation.ValidationUtils.rejectIfEmptyOrWhitespace(ValidationUtils.java:252) at org.springframework.validation.ValidationUtils.rejectIfEmptyOrWhitespace(ValidationUtils.java:191) at sg.gov.hpb.yhms.medical_service.validators.AllergyDtoValidator.validate(AllergyDtoValidator.java:32) at org.springframework.validation.ValidationUtils.invokeValidator(ValidationUtils.java:89) at org.springframework.validation.ValidationUtils.invokeValidator(ValidationUtils.java:56) at sg.gov.hpb.yhms.medical_service.validators.AllergyDtoListValidator.validate(AllergyDtoListValidator.java:32)

CodePudding user response:

org.springframework.validation.Validator cannot validate List<Object> as a target. You must wrap the List in a single Object with getter to let validator to find a path to access sub objects.

public class AllergyDtoListValidator implements Validator {

  private AllergyDtoValidator allergyDtoValidator;

  @Override
  public boolean supports(Class<?> clazz) {
    return AllergyDtoList.class.isAssignableFrom(clazz);
  }

  @Override
  public void validate(Object target, Errors errors) {
    allergyDtoValidator = new AllergyDtoValidator();
    AllergyDtoList request = (AllergyDtoList) target;
    for (int i = 0; i < request.size(); i  ) {
      // sub path name must be same as property name to enable Validator to use 
      // getter in the object AllergyDtoList
      errors.pushNestedPath("allergies[" i "]");
      ValidationUtils.invokeValidator(this.allergyDtoValidator, request.get(i), errors);
      errors.popNestedPath();
    }
  }
}

// new wrapping object to be validated 
class AllergyDtoList {

    List<AllergyDto> allergies;
}
  •  Tags:  
  • Related