[ 
https://issues.apache.org/jira/browse/BEANUTILS-541?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Sergey Chernov updated BEANUTILS-541:
-------------------------------------
    Description: 
There is an issue in {{FluentPropertyBeanIntrospector}} (at line 144 for 
1.9.3), it caches wrong writeMethod in the static cache of 
{{java.beans.Introspector when base class (with chained setter) has at least 
two subclasses}}. Simple snippet to reproduce:

{code:java}
import org.apache.commons.beanutils.FluentPropertyBeanIntrospector;
import org.apache.commons.beanutils.PropertyUtilsBean;

public class BeanUtilsTest {

    public static void main(String[] args) throws Exception {
        PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
        propertyUtilsBean.addBeanIntrospector(new 
FluentPropertyBeanIntrospector());

        // invert if condition and it will succeed
        if (true) {
            // fails

            SubTypeA subTypeA = new SubTypeA();
            //subTypeA.setField("name");
            propertyUtilsBean.setProperty(subTypeA, "field", "name");

            // uncomment this line and the failure will be handled (workaround)
            //java.beans.Introspector.flushCaches();

            SubTypeB subTypeB = new SubTypeB();
            //subTypeB.setField("name");
            propertyUtilsBean.setProperty(subTypeB, "field", "name");
        } else {
            // the same as above, but reverse order - success

            SubTypeB subTypeB = new SubTypeB();
            //subTypeB.setField("name");
            propertyUtilsBean.setProperty(subTypeB, "field", "name");

            SubTypeA subTypeA = new SubTypeA();
            //subTypeA.setField("name");
            propertyUtilsBean.setProperty(subTypeA, "field", "name");
        }
    }

    public static class BaseType {

        private String field;

        public BaseType setField(String objectName) {
            this.field = objectName;
            // pay attention - setter returns self object (not void)
            return this;
        }

        public String getField() {
            return field;
        }
    }

    public static class SubTypeA extends BaseType {

        @Override
        public SubTypeA setField(String field) {
            super.setField(field);
            return this;
        }
    }

    public static class SubTypeB extends BaseType {

    }
}
{code}
 
It is critical, because wrong information is stored globally unless explicit 
{{Introspector.flushCaches}} ({{Introspector.flushFromCaches}}) is called.

Failure stacktrace:
{code}
Exception in thread "main" java.lang.IllegalArgumentException: 
org.jeasy.random.BeanUtilsTest$SubTypeB is not assignable from 
org.jeasy.random.BeanUtilsTest$SubTypeA
        at 
org.apache.commons.beanutils.MethodUtils.getAccessibleMethod(MethodUtils.java:793)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.getWriteMethod(PropertyUtilsBean.java:1319)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2094)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1915)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2022)
        at org.jeasy.random.BeanUtilsTest.main(BeanUtilsTest.java:44)
{code}

  was:
There is an issue in {{FluentPropertyBeanIntrospector}} (at line 144 for 
1.9.3), it caches wrong writeMethod in the static cache of 
{{java.beans.Introspector when base class (with chained setter) has at least 
two subclasses}}. Simple snippet to reproduce:

{code:java}
import org.apache.commons.beanutils.FluentPropertyBeanIntrospector;
import org.apache.commons.beanutils.PropertyUtilsBean;

public class BeanUtilsTest {

    public static void main(String[] args) throws Exception {
        PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
        propertyUtilsBean.addBeanIntrospector(new 
FluentPropertyBeanIntrospector());

        // invert if condition and it will succeed
        if (true) {
            // fails

            SubTypeA subTypeA = new SubTypeA();
            //subTypeA.setField("name");
            propertyUtilsBean.setProperty(subTypeA, "field", "name");

            // uncomment this line and the failure will be handled (workaround)
            //java.beans.Introspector.flushCaches();

            SubTypeB subTypeB = new SubTypeB();
            //subTypeB.setField("name");
            propertyUtilsBean.setProperty(subTypeB, "field", "name");
        } else {
            // the same as above, but reverse order - success

            SubTypeB subTypeB = new SubTypeB();
            //subTypeB.setField("name");
            propertyUtilsBean.setProperty(subTypeB, "field", "name");

            SubTypeA subTypeA = new SubTypeA();
            //subTypeA.setField("name");
            propertyUtilsBean.setProperty(subTypeA, "field", "name");
        }
    }

    public static class BaseType {

        private String field;

        public BaseType setField(String objectName) {
            this.field = objectName;
            return this;
        }

        public String getField() {
            return field;
        }
    }

    public static class SubTypeA extends BaseType {

        @Override
        public SubTypeA setField(String field) {
            super.setField(field);
            return this;
        }
    }

    public static class SubTypeB extends BaseType {

    }
}
{code}
 
It is critical, because wrong information is stored globally unless explicit 
{{Introspector.flushCaches}} ({{Introspector.flushFromCaches}}) is called.

Failure stacktrace:
{code}
Exception in thread "main" java.lang.IllegalArgumentException: 
org.jeasy.random.BeanUtilsTest$SubTypeB is not assignable from 
org.jeasy.random.BeanUtilsTest$SubTypeA
        at 
org.apache.commons.beanutils.MethodUtils.getAccessibleMethod(MethodUtils.java:793)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.getWriteMethod(PropertyUtilsBean.java:1319)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2094)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1915)
        at 
org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2022)
        at org.jeasy.random.BeanUtilsTest.main(BeanUtilsTest.java:44)
{code}


> FluentPropertyBeanIntrospector caches corrupted writeMethod (two subclasses)
> ----------------------------------------------------------------------------
>
>                 Key: BEANUTILS-541
>                 URL: https://issues.apache.org/jira/browse/BEANUTILS-541
>             Project: Commons BeanUtils
>          Issue Type: Bug
>          Components: Bean / Property Utils
>    Affects Versions: 1.9.0, 1.9.1, 1.9.2, 1.9.3, 1.9.4
>            Reporter: Sergey Chernov
>            Priority: Blocker
>
> There is an issue in {{FluentPropertyBeanIntrospector}} (at line 144 for 
> 1.9.3), it caches wrong writeMethod in the static cache of 
> {{java.beans.Introspector when base class (with chained setter) has at least 
> two subclasses}}. Simple snippet to reproduce:
> {code:java}
> import org.apache.commons.beanutils.FluentPropertyBeanIntrospector;
> import org.apache.commons.beanutils.PropertyUtilsBean;
> public class BeanUtilsTest {
>     public static void main(String[] args) throws Exception {
>         PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
>         propertyUtilsBean.addBeanIntrospector(new 
> FluentPropertyBeanIntrospector());
>         // invert if condition and it will succeed
>         if (true) {
>             // fails
>             SubTypeA subTypeA = new SubTypeA();
>             //subTypeA.setField("name");
>             propertyUtilsBean.setProperty(subTypeA, "field", "name");
>             // uncomment this line and the failure will be handled 
> (workaround)
>             //java.beans.Introspector.flushCaches();
>             SubTypeB subTypeB = new SubTypeB();
>             //subTypeB.setField("name");
>             propertyUtilsBean.setProperty(subTypeB, "field", "name");
>         } else {
>             // the same as above, but reverse order - success
>             SubTypeB subTypeB = new SubTypeB();
>             //subTypeB.setField("name");
>             propertyUtilsBean.setProperty(subTypeB, "field", "name");
>             SubTypeA subTypeA = new SubTypeA();
>             //subTypeA.setField("name");
>             propertyUtilsBean.setProperty(subTypeA, "field", "name");
>         }
>     }
>     public static class BaseType {
>         private String field;
>         public BaseType setField(String objectName) {
>             this.field = objectName;
>             // pay attention - setter returns self object (not void)
>             return this;
>         }
>         public String getField() {
>             return field;
>         }
>     }
>     public static class SubTypeA extends BaseType {
>         @Override
>         public SubTypeA setField(String field) {
>             super.setField(field);
>             return this;
>         }
>     }
>     public static class SubTypeB extends BaseType {
>     }
> }
> {code}
>  
> It is critical, because wrong information is stored globally unless explicit 
> {{Introspector.flushCaches}} ({{Introspector.flushFromCaches}}) is called.
> Failure stacktrace:
> {code}
> Exception in thread "main" java.lang.IllegalArgumentException: 
> org.jeasy.random.BeanUtilsTest$SubTypeB is not assignable from 
> org.jeasy.random.BeanUtilsTest$SubTypeA
>       at 
> org.apache.commons.beanutils.MethodUtils.getAccessibleMethod(MethodUtils.java:793)
>       at 
> org.apache.commons.beanutils.PropertyUtilsBean.getWriteMethod(PropertyUtilsBean.java:1319)
>       at 
> org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2094)
>       at 
> org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1915)
>       at 
> org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2022)
>       at org.jeasy.random.BeanUtilsTest.main(BeanUtilsTest.java:44)
> {code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to