You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Alexander Kovalenko (JIRA)" <ji...@apache.org> on 2009/01/16 10:42:01 UTC

[jira] Created: (DIGESTER-133) Class fields are not set if class is inherited from HashMap if commons-beanutils-1.8.0 is used

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

                 Key: DIGESTER-133
                 URL: https://issues.apache.org/jira/browse/DIGESTER-133
             Project: Commons Digester
          Issue Type: Bug
    Affects Versions: 2.0, 1.8, 1.7, 1.6
         Environment: OS: Kubuntu 8.0.4, Java version is 1.5.0_15
Windows XP, Java version 1.5.0_11-b03
            Reporter: Alexander Kovalenko
            Priority: Minor


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());
	}
}


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Issue Comment Edited: (DIGESTER-133) Class fields are not set if class is inherited from HashMap if commons-beanutils-1.8.0 is used

Posted by "Niall Pemberton (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/DIGESTER-133?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12664671#action_12664671 ] 

niallp edited comment on DIGESTER-133 at 1/16/09 1:22 PM:
-------------------------------------------------------------------

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

{code}
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);
        }
    }
}
{code}

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

{code}
MyPropertyUtilsBean.initMyPropertyUtilsBean();
{code}

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

      was (Author: niallp):
    The problem in BeanUtils is that the behaviour towards Maps that also had 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

{code}
package org.myco.myproj;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtilsBean;

public class MyPropertyUtilsBean extends PropertyUtilsBean {

    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);
        }
    }
}
{code}

You can then register your custom implementation in the following way:

{code}
        PropertyUtilsBean propertyUtils = new MyPropertyUtilsBean();
        ConvertUtilsBean convertUtils = new ConvertUtilsBean();
        BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils, propertyUtils);
        BeanUtilsBean.setInstance(beanUtils);
{code}

The both BeanUtils and PropertyUtils should both delegate to your custom bean and get the behaviour you want.
  
> Class fields are not set if class is inherited from HashMap if commons-beanutils-1.8.0 is used
> ----------------------------------------------------------------------------------------------
>
>                 Key: DIGESTER-133
>                 URL: https://issues.apache.org/jira/browse/DIGESTER-133
>             Project: Commons Digester
>          Issue Type: Bug
>    Affects Versions: 1.6, 1.7, 1.8, 2.0
>         Environment: OS: Kubuntu 8.0.4, Java version is 1.5.0_15
> Windows XP, Java version 1.5.0_11-b03
>            Reporter: Alexander Kovalenko
>            Priority: Minor
>
> 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());
> 	}
> }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.