Author: oheger
Date: Sun Nov 11 19:03:58 2012
New Revision: 1408085
URL: http://svn.apache.org/viewvc?rev=1408085&view=rev
Log:
[CONFIGURATION-514] DefaultBeanFactory now supports creating beans by invoking
a constructor.
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanFactory.java
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/beanutils/TestDefaultBeanFactory.java
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanFactory.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanFactory.java?rev=1408085&r1=1408084&r2=1408085&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanFactory.java
(original)
+++
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanFactory.java
Sun Nov 11 19:03:58 2012
@@ -16,6 +16,12 @@
*/
package org.apache.commons.configuration.beanutils;
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.commons.configuration.PropertyConverter;
+
/**
* <p>
* The default implementation of the {@code BeanFactory} interface.
@@ -89,7 +95,9 @@ public class DefaultBeanFactory implemen
protected Object createBeanInstance(Class<?> beanClass, BeanDeclaration
data)
throws Exception
{
- return beanClass.newInstance();
+ Constructor<?> ctor = BeanHelper.findMatchingConstructor(beanClass,
data);
+ Object[] args = fetchConstructorArgs(ctor, data);
+ return ctor.newInstance(args);
}
/**
@@ -107,4 +115,52 @@ public class DefaultBeanFactory implemen
{
BeanHelper.initBean(bean, data);
}
+
+ /**
+ * Obtains the arguments for a constructor call to create a bean. This
method
+ * resolves nested bean declarations and performs necessary type
+ * conversions.
+ *
+ * @param ctor the constructor to be invoked
+ * @param data the current bean declaration
+ * @return an array with constructor arguments
+ */
+ private static Object[] fetchConstructorArgs(Constructor<?> ctor,
+ BeanDeclaration data)
+ {
+ Class<?>[] types = ctor.getParameterTypes();
+ assert types.length == nullSafeConstructorArgs(data).size() :
+ "Wrong number of constructor arguments!";
+ Object[] args = new Object[types.length];
+ int idx = 0;
+
+ for (ConstructorArg arg : nullSafeConstructorArgs(data))
+ {
+ Object val =
+ arg.isNestedBeanDeclaration() ? BeanHelper.createBean(arg
+ .getBeanDeclaration()) : arg.getValue();
+ args[idx] = PropertyConverter.to(types[idx], val, null);
+ idx++;
+ }
+
+ return args;
+ }
+
+ /**
+ * Fetches constructor arguments from the given bean declaration. Handles
+ * <b>null</b> values safely.
+ *
+ * @param data the bean declaration
+ * @return the collection with constructor arguments (never <b>null</b>)
+ */
+ private static Collection<ConstructorArg> nullSafeConstructorArgs(
+ BeanDeclaration data)
+ {
+ Collection<ConstructorArg> args = data.getConstructorArgs();
+ if (args == null)
+ {
+ args = Collections.emptySet();
+ }
+ return args;
+ }
}
Modified:
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/beanutils/TestDefaultBeanFactory.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/beanutils/TestDefaultBeanFactory.java?rev=1408085&r1=1408084&r2=1408085&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/beanutils/TestDefaultBeanFactory.java
(original)
+++
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/beanutils/TestDefaultBeanFactory.java
Sun Nov 11 19:03:58 2012
@@ -21,7 +21,9 @@ import static org.junit.Assert.assertNot
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -41,7 +43,7 @@ import org.junit.Test;
public class TestDefaultBeanFactory
{
/** The object to be tested. */
- DefaultBeanFactory factory;
+ private DefaultBeanFactory factory;
@Before
public void setUp() throws Exception
@@ -64,8 +66,12 @@ public class TestDefaultBeanFactory
@Test
public void testCreateBean() throws Exception
{
+ BeanDeclarationTestImpl decl = new BeanDeclarationTestImpl();
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("throwExceptionOnMissing", Boolean.TRUE);
+ decl.setBeanProperties(props);
Object bean = factory.createBean(PropertiesConfiguration.class,
- new TestBeanDeclaration(), null);
+ decl, null);
assertNotNull("New bean is null", bean);
assertEquals("Bean is of wrong class", PropertiesConfiguration.class,
bean.getClass());
@@ -75,40 +81,44 @@ public class TestDefaultBeanFactory
}
/**
- * A simple implementation of BeanDeclaration used for testing purposes.
+ * Tests whether a bean can be created by calling its constructor.
*/
- static class TestBeanDeclaration implements BeanDeclaration
+ @Test
+ public void testCreateBeanConstructor() throws Exception
+ {
+ BeanDeclarationTestImpl decl = new BeanDeclarationTestImpl();
+ Collection<ConstructorArg> args = new ArrayList<ConstructorArg>();
+ args.add(ConstructorArg.forValue("test"));
+ args.add(ConstructorArg.forValue("42"));
+ decl.setConstructorArgs(args);
+ BeanCreationTestCtorBean bean =
+ (BeanCreationTestCtorBean) factory.createBean(
+ BeanCreationTestCtorBean.class, decl, null);
+ assertEquals("Wrong string property", "test", bean.getStringValue());
+ assertEquals("Wrong int property", 42, bean.getIntValue());
+ }
+
+ /**
+ * Tests whether nested bean declarations in constructor arguments are
taken
+ * into account.
+ */
+ @Test
+ public void testCreateBeanConstructorNestedBean() throws Exception
{
- public String getBeanFactoryName()
- {
- return null;
- }
-
- public Object getBeanFactoryParameter()
- {
- return null;
- }
-
- public String getBeanClassName()
- {
- return null;
- }
-
- public Map<String, Object> getBeanProperties()
- {
- Map<String, Object> props = new HashMap<String, Object>();
- props.put("throwExceptionOnMissing", Boolean.TRUE);
- return props;
- }
-
- public Map<String, Object> getNestedBeanDeclarations()
- {
- return null;
- }
-
- public Collection<ConstructorArg> getConstructorArgs()
- {
- return null;
- }
+ BeanDeclarationTestImpl declNested = new BeanDeclarationTestImpl();
+ Collection<ConstructorArg> args = new ArrayList<ConstructorArg>();
+ args.add(ConstructorArg.forValue("test", String.class.getName()));
+ declNested.setConstructorArgs(args);
+ declNested.setBeanClassName(BeanCreationTestCtorBean.class.getName());
+ BeanDeclarationTestImpl decl = new BeanDeclarationTestImpl();
+ decl.setConstructorArgs(Collections.singleton(ConstructorArg
+ .forBeanDeclaration(declNested,
+ BeanCreationTestBean.class.getName())));
+ BeanCreationTestCtorBean bean =
+ (BeanCreationTestCtorBean) factory.createBean(
+ BeanCreationTestCtorBean.class, decl, null);
+ assertNotNull("Buddy bean was not set", bean.getBuddy());
+ assertEquals("Wrong property of buddy bean", "test", bean.getBuddy()
+ .getStringValue());
}
}