Commons Digester
  1. Commons Digester
  2. DIGESTER-133

Class fields are not set if class is inherited from HashMap if commons-beanutils-1.8.0 is used

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 1.6, 1.7, 1.8, 2.0
    • Fix Version/s: 3.0
    • Labels:
      None
    • Environment:

      OS: Kubuntu 8.0.4, Java version is 1.5.0_15
      Windows XP, Java version 1.5.0_11-b03

      Description

      Class fields are not set if class is inherited from HashMap, value is put in HashMap instead.
      I tried this simple test with Digester 1.6, 1.7, 1.8 and 2.0. It works with commons-beanutils-1.7.0, but does not work with commons-beanutils-1.8.0. JUnit 4.4 was used for testing.

      ================ Class to be instantiated from XML ==========================
      import java.util.HashMap;

      public class MyClass extends HashMap<String, String> {
      private boolean flag = false;

      public boolean isFlag()

      { return flag; }

      public void setFlag(boolean flag)

      { this.flag = flag; }

      }

      ================= Test ===================
      import static org.junit.Assert.assertTrue;

      import java.io.ByteArrayInputStream;
      import java.io.IOException;

      import org.apache.commons.digester.Digester;
      import org.junit.Test;
      import org.xml.sax.SAXException;

      public class TestDigester {

      @Test
      public void testDigester() throws IOException, SAXException

      { final String xml = "<myclass flag='true'/>"; final Digester digester = new Digester(); digester.addObjectCreate("myclass", MyClass.class); digester.addSetProperties("myclass"); final MyClass res = (MyClass) digester.parse(new ByteArrayInputStream(xml.getBytes())); assertTrue(res.isFlag()); }

      }

        Issue Links

          Activity

          Hide
          Simone Tripodi added a comment -

          included in Apache Commons Digester 3.0 release

          Show
          Simone Tripodi added a comment - included in Apache Commons Digester 3.0 release
          Hide
          Simone Tripodi added a comment -

          Niall's hint works, please see committed Digester133TestCase on Digester3

          Show
          Simone Tripodi added a comment - Niall's hint works, please see committed Digester133TestCase on Digester3
          Hide
          Niall Pemberton added a comment - - edited

          The problem in BeanUtils was that the behaviour towards Maps that also have properties was inconsistent and the decision was taken to make everything consistent with the principle that "Maps are always treated as Maps". See BEANUTILS-162 for a full discussion on this.

          As part of fixing that issue two methods were added to PropertyUtilsBean to make it easier for people to change this behaviour with their own custom implementation of PropertyUtilsBean:

          So you can create your own PropertyUtilsBean implementation, something like the following

          package org.myco.myproj;
          
          import java.lang.reflect.InvocationTargetException;
          import java.util.Map;
          
          import org.apache.commons.beanutils.BeanUtilsBean;
          import org.apache.commons.beanutils.ConvertUtilsBean;
          import org.apache.commons.beanutils.PropertyUtilsBean;
          
          public class MyPropertyUtilsBean extends PropertyUtilsBean {
          
              public static void initMyPropertyUtilsBean() {
                  PropertyUtilsBean propertyUtils = new MyPropertyUtilsBean();
                  ConvertUtilsBean convertUtils = new ConvertUtilsBean();
                  BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils, propertyUtils);
                  BeanUtilsBean.setInstance(beanUtils);
              }
          
              protected Object getPropertyOfMapBean(Map bean, String name)
                  throws IllegalArgumentException, IllegalAccessException,
                  InvocationTargetException, NoSuchMethodException {
          
                  if (isReadable(bean, name)) {
                      return getSimpleProperty(bean, name);
                  } else {
                      return super.getPropertyOfMapBean(bean, name);
                  }
              }
          
              protected void setPropertyOfMapBean(Map bean, String name, Object value)
                  throws IllegalArgumentException, IllegalAccessException,
                         InvocationTargetException, NoSuchMethodException {
                  if (isWriteable(bean, name)) {
                      setSimpleProperty(bean, name, value);
                  } else {
                      super.setPropertyOfMapBean(bean, name, value);
                  }
              }
          }
          

          I included a static method in the above to register your custom PropertyUtilsBean implementation

          MyPropertyUtilsBean.initMyPropertyUtilsBean();
          

          Then both BeanUtils and PropertyUtils should both delegate to your custom bean and get the behaviour you want.

          Show
          Niall Pemberton added a comment - - edited The problem in BeanUtils was that the behaviour towards Maps that also have properties was inconsistent and the decision was taken to make everything consistent with the principle that "Maps are always treated as Maps". See BEANUTILS-162 for a full discussion on this. As part of fixing that issue two methods were added to PropertyUtilsBean to make it easier for people to change this behaviour with their own custom implementation of PropertyUtilsBean: getPropertyOfMapBean() - See http://tinyurl.com/9jvjec setPropertyOfMapBean() - See http://tinyurl.com/7d9ynj So you can create your own PropertyUtilsBean implementation, something like the following package org.myco.myproj; import java.lang.reflect.InvocationTargetException; import java.util.Map; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.ConvertUtilsBean; import org.apache.commons.beanutils.PropertyUtilsBean; public class MyPropertyUtilsBean extends PropertyUtilsBean { public static void initMyPropertyUtilsBean() { PropertyUtilsBean propertyUtils = new MyPropertyUtilsBean(); ConvertUtilsBean convertUtils = new ConvertUtilsBean(); BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils, propertyUtils); BeanUtilsBean.setInstance(beanUtils); } protected Object getPropertyOfMapBean(Map bean, String name) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { if (isReadable(bean, name)) { return getSimpleProperty(bean, name); } else { return super .getPropertyOfMapBean(bean, name); } } protected void setPropertyOfMapBean(Map bean, String name, Object value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { if (isWriteable(bean, name)) { setSimpleProperty(bean, name, value); } else { super .setPropertyOfMapBean(bean, name, value); } } } I included a static method in the above to register your custom PropertyUtilsBean implementation MyPropertyUtilsBean.initMyPropertyUtilsBean(); Then both BeanUtils and PropertyUtils should both delegate to your custom bean and get the behaviour you want.

            People

            • Assignee:
              Simone Tripodi
              Reporter:
              Alexander Kovalenko
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development