Author: henning Date: Mon Oct 21 22:02:27 2013 New Revision: 1534393 URL: http://svn.apache.org/r1534393 Log: Backport COLLECTIONS-546 from r1492404.
Added: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.java (with props) commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.java (with props) Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.java commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/TestBeanHelper.java Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt?rev=1534393&r1=1534392&r2=1534393&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt Mon Oct 21 22:02:27 2013 @@ -36,9 +36,11 @@ BUG FIXES IN 1.10 XMLConfiguration now adds attributes of elements defining a list to all list nodes. -* [CONFIGURATION-550] Missing conversion to char +* [CONFIGURATION-546] ClassCastException in BeanHelper constructing beans with a list + of child beans. - Conversion to Character is now supported. + BeanHelper can now process BeanDefinitions initializing properties of + collection types of their target beans. * [CONFIGURATION-555] XMLConfiguration doesn't seem to be preserving whitespace for the current node where xml:space="preserve" is set. @@ -72,5 +74,10 @@ BUG FIXES IN 1.10 IMPROVEMENTS AND NEW FEATURES IN 1.10 ===================================== +* [CONFIGURATION-550] Missing conversion to char + + Conversion to Character is now supported. + + OTHER CHANGES ============= Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml?rev=1534393&r1=1534392&r2=1534393&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml Mon Oct 21 22:02:27 2013 @@ -31,6 +31,10 @@ XMLConfiguration now adds attributes of elements defining a list to all list nodes. </action> + <action dev="oheger" type="update" issue="CONFIGURATION-546" due-to="Justin Couch"> + BeanHelper can now process BeanDefinitions initializing properties of + collection types of their target beans. + </action> <action dev="oheger" type="add" issue="CONFIGURATION-550"> Conversion to Character is now supported. </action> Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.java?rev=1534393&r1=1534392&r2=1534393&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.java (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.java Mon Oct 21 22:02:27 2013 @@ -18,12 +18,14 @@ package org.apache.commons.configuration import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtils; @@ -203,8 +205,27 @@ public final class BeanHelper { String propName = e.getKey(); Class<?> defaultClass = getDefaultClass(bean, propName); - initProperty(bean, propName, createBean( - (BeanDeclaration) e.getValue(), defaultClass)); + + Object prop = e.getValue(); + + if (prop instanceof Collection) + { + Collection<Object> beanCollection = + createPropertyCollection(propName, defaultClass); + + for (Object elemDef : (Collection<?>) prop) + { + beanCollection + .add(createBean((BeanDeclaration) elemDef)); + } + + initProperty(bean, propName, beanCollection); + } + else + { + initProperty(bean, propName, createBean( + (BeanDeclaration) e.getValue(), defaultClass)); + } } } } @@ -287,6 +308,39 @@ public final class BeanHelper } /** + * Creates a concrete collection instance to populate a property of type + * collection. This method tries to guess an appropriate collection type. + * Mostly the type of the property will be one of the collection interfaces + * rather than a concrete class; so we have to create a concrete equivalent. + * + * @param propName the name of the collection property + * @param propertyClass the type of the property + * @return the newly created collection + */ + private static Collection<Object> createPropertyCollection(String propName, + Class<?> propertyClass) + { + Collection<Object> beanCollection = null; + + if (List.class.isAssignableFrom(propertyClass)) + { + beanCollection = new ArrayList<Object>(); + } + else if (Set.class.isAssignableFrom(propertyClass)) + { + beanCollection = new TreeSet<Object>(); + } + else + { + throw new UnsupportedOperationException( + "Unable to handle collection of type : " + + propertyClass.getName() + " for property " + + propName); + } + return beanCollection; + } + + /** * Set a property on the bean only if the property exists * * @param bean the bean Added: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.java?rev=1534393&view=auto ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.java (added) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.java Mon Oct 21 22:02:27 2013 @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.configuration.beanutils; + +/** + * A simple bean class used for testing bean creation operations. + * + * @version $Id$ + */ +public class BeanCreationTestBean +{ + private String stringValue; + + private int intValue; + + private BeanCreationTestBean buddy; + + public BeanCreationTestBean getBuddy() + { + return buddy; + } + + public void setBuddy(BeanCreationTestBean buddy) + { + this.buddy = buddy; + } + + public int getIntValue() + { + return intValue; + } + + public void setIntValue(int intValue) + { + this.intValue = intValue; + } + + public String getStringValue() + { + return stringValue; + } + + public void setStringValue(String stringValue) + { + this.stringValue = stringValue; + } +} Propchange: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.java ------------------------------------------------------------------------------ svn:keywords = Id Author Date Revision Added: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.java?rev=1534393&view=auto ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.java (added) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.java Mon Oct 21 22:02:27 2013 @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.configuration.beanutils; + +import java.util.ArrayList; +import java.util.List; + +/** + * A simple bean class used for testing bean creation operations that has + * a list of children of a different bean type. + * + * @version $Id$ + */ +public class BeanCreationTestBeanWithListChild +{ + private String stringValue; + + private int intValue; + + private List<BeanCreationTestBean> children = new ArrayList<BeanCreationTestBean>(); + + public List<BeanCreationTestBean> getChildren() + { + return children; + } + + public void setChildren(List<BeanCreationTestBean> buddies) + { + this.children.clear(); + this.children.addAll(buddies); + } + + public int getIntValue() + { + return intValue; + } + + public void setIntValue(int intValue) + { + this.intValue = intValue; + } + + public String getStringValue() + { + return stringValue; + } + + public void setStringValue(String stringValue) + { + this.stringValue = stringValue; + } +} Propchange: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.java ------------------------------------------------------------------------------ svn:keywords = Id Author Date Revision Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/TestBeanHelper.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/TestBeanHelper.java?rev=1534393&r1=1534392&r2=1534393&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/TestBeanHelper.java (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/beanutils/TestBeanHelper.java Mon Oct 21 22:02:27 2013 @@ -22,7 +22,9 @@ import static org.junit.Assert.assertNul import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.commons.configuration.ConfigurationRuntimeException; @@ -41,6 +43,12 @@ import org.junit.Test; */ public class TestBeanHelper { + /** Constant for the test value of the string property. */ + private static final String TEST_STRING = "testString"; + + /** Constant for the test value of the numeric property. */ + private static final int TEST_INT = 42; + /** Constant for the name of the test bean factory. */ private static final String TEST_FACTORY = "testFactory"; @@ -207,6 +215,18 @@ public class TestBeanHelper assertNull("A parameter was passed", factory.parameter); } + @Test + public void testCreateBeanWithListChildBean() + { + TestBeanFactory factory = new TestBeanFactory(); + BeanHelper.registerBeanFactory(TEST_FACTORY, factory); + TestBeanDeclaration data = setUpBeanDeclarationWithListChild(); + data.setBeanFactoryName(TEST_FACTORY); + data.setBeanClassName(BeanCreationTestBeanWithListChild.class.getName()); + checkBean((BeanCreationTestBeanWithListChild) BeanHelper.createBean(data, null)); + assertNull("A parameter was passed", factory.parameter); + } + /** * Tests creating a bean when no bean declaration is provided. This should * cause an exception. @@ -347,6 +367,7 @@ public class TestBeanHelper { buddyData.setBeanFactoryName(TEST_FACTORY); } + Map<String, Object> nested = new HashMap<String, Object>(); nested.put("buddy", buddyData); data.setNestedBeanDeclarations(nested); @@ -354,6 +375,53 @@ public class TestBeanHelper } /** + * Same as setUpBeanDeclaration, but returns a nested array of beans + * as a single property. Tests multi-value (Collection<BeanDeclaration>) + * children construction. + * + * @return The bean declaration with a list child bean proerty + */ + private TestBeanDeclaration setUpBeanDeclarationWithListChild() + { + TestBeanDeclaration data = new TestBeanDeclaration(); + Map<String, Object> properties = new HashMap<String, Object>(); + properties.put("stringValue", TEST_STRING); + properties.put("intValue", String.valueOf(TEST_INT)); + data.setBeanProperties(properties); + + List<BeanDeclaration> childData = new ArrayList<BeanDeclaration>(); + childData.add(createChildBean("child1")); + childData.add(createChildBean("child2")); + Map<String, Object> nested = new HashMap<String, Object>(); + nested.put("children", childData); + data.setNestedBeanDeclarations(nested); + return data; + } + + /** + * Create a simple bean declaration that has no children for testing + * of nested children bean declarations. + * + * @param name A name prefix that can be used to disambiguate the children + * @return A simple declaration + */ + private TestBeanDeclaration createChildBean(String name) + { + TestBeanDeclaration childBean = new TestBeanDeclaration(); + Map<String, Object> properties2 = new HashMap<String, Object>(); + properties2.put("stringValue", name + " Another test string"); + properties2.put("intValue", new Integer(100)); + childBean.setBeanProperties(properties2); + childBean.setBeanClassName(BeanCreationTestBean.class.getName()); + if (BeanHelper.getDefaultBeanFactory() == null) + { + childBean.setBeanFactoryName(TEST_FACTORY); + } + + return childBean; + } + + /** * Tests if the bean was correctly initialized from the data of the test * bean declaration. * @@ -414,6 +482,24 @@ public class TestBeanHelper } /** + * Tests if the bean was correctly initialized from the data of the test + * bean declaration. + * + * @param bean the bean to be checked + */ + private void checkBean(BeanCreationTestBeanWithListChild bean) + { + assertEquals("Wrong string property", TEST_STRING, bean + .getStringValue()); + assertEquals("Wrong int property", TEST_INT, bean.getIntValue()); + List<BeanCreationTestBean> children = bean.getChildren(); + assertNotNull("Children were not set", children); + assertEquals("Wrong number of children created", children.size(), 2); + assertNotNull("First child was set as null", children.get(0)); + assertNotNull("Second child was set as null", children.get(1)); + } + + /** * An implementation of the BeanFactory interface used for testing. This * implementation is really simple: If the TestBean class is provided, a new * instance will be created. Otherwise an exception is thrown. @@ -434,6 +520,12 @@ public class TestBeanHelper BeanHelper.initBean(bean, data); return bean; } + else if (BeanCreationTestBeanWithListChild.class.equals(beanClass)) + { + BeanCreationTestBeanWithListChild bean = new BeanCreationTestBeanWithListChild(); + BeanHelper.initBean(bean, data); + return bean; + } else { throw new IllegalArgumentException("Unsupported class: "