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;
}