org.springframework.beans.NotReadablePropertyException: Invalid property 'entries[0].reason' of bean class [my.company.data.SDROrder]: Bean property 'entries[0].reason' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
this was thrown with following code snippet
Errors errors = new BeanPropertyBindingResult(new SDROrder(), "sdr");
orderValidator.validate(order, errors);
and this is my OrderValidatior implementation
public class OrderValidator implements Validator
{
@Override
public boolean supports(Class<?> clazz)
{
return Order.class.isAssignableFrom(clazz);
}
@Override
public void validate(final Object target, final Errors errors)
{
errors.rejectValue("entries[0].reason", "Wrong Reason");
}
}
the problem was at
errors.rejectValue("entries[0].reason", "Wrong Reason");
apparently Spring can't understand that entries[0] is of type SDROrder but not Order that hasn't reason attribute in it. Let's see data hierarchy
public class Order
{
private List<AbstractOrderEntry> entries;
public List<AbstractOrderEntry> getEntries()
{
return entries;
}
public void setEntries(List<AbstractOrderEntry> entries)
{
this.entries = entries;
}
}
public class SDROrder extends Order {}
public class AbstractOrderEntry {}
So how to explain Spring to use child but not parent here? Does Spring understand hierarchies of objects? Why Spring doesn't uses late binding here?!
All these questions were in my mind for a long time. Finally I found the solution...
The trick is at
org.springframework.validation.Errors.pushNestedPath(String)and
org.springframework.validation.Errors.popNestedPath()methods. The correct validation should be done as follow:
errors.pushNestedPath("entries[0]");
errors.rejectValue("reason", "Wrong Reason");
errors.popNestedPath();
and that's it!
You may find sources for wrong approach mentioned here at link
and of course correct approach is here
Hope it will save time to someone!