Skip to content

PropertyDescriptorUtils randomly fails to determine read/write method pairs with partially resolved generics and overloaded write methods #36019

@zhanhcs

Description

@zhanhcs

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()) {

Metadata

Metadata

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)status: feedback-providedFeedback has been providedstatus: waiting-for-triageAn issue we've not yet triaged or decided on

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions