`PropertyDescriptorUtils` does not reliably resolve read/write methods in type hierarchies with generics
Overview
- jdk21
- Spring 6.2.11
In the following case, the setId(int id) method is inconsistent with the generic type String, and since it implements two interfaces, random copying failures may occur.
The methods of the IModel class cannot change their order; doing so may prevent this issue from being reproduced.
public class BeanUtilsCopyPropertiesTests { public static class BaseModel<T> { public BaseModel() { } private T id; /** * @return the id */ public T getId() { return id; } /** * @param id the id to set */ public void setId(T id) { this.id = id; } } interface IModel<T>{ void setId(T id); T getId(); } interface A<T> extends IModel<T>{ } interface B<T> extends IModel<T>{ } public static class User extends BaseModel<String> implements A<String>,B<String> { public User() { super(); } @Override public String getId() { return super.getId(); } public void setId(int id) { setId(String.valueOf(id)); } } @org.junit.jupiter.api.Test public void testCopyFailed(){ User source = new User(); source.setId(1); User target = new User(); BeanUtils.copyProperties(source, target); assertEquals(source.getId(), target.getId()); } }
Analysis
Root cause : PropertyDescriptorUtils
This is caused by the inconsistent order returned by the Class#getMethods.
public static Collection<? extends PropertyDescriptor> determineBasicProperties(Class<?> beanClass) throws IntrospectionException { Map<String, BasicPropertyDescriptor> pdMap = new TreeMap<>(); for (Method method : beanClass.getMethods()) {