| /* |
| * 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 |
| * |
| * https://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.configuration2.beanutils; |
| |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertSame; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| import static org.mockito.Mockito.mock; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.commons.beanutils.DynaBean; |
| import org.apache.commons.beanutils.LazyDynaBean; |
| import org.apache.commons.configuration2.PropertiesConfiguration; |
| import org.apache.commons.configuration2.ex.ConfigurationRuntimeException; |
| import org.junit.jupiter.api.BeforeEach; |
| import org.junit.jupiter.api.Test; |
| |
| /** |
| * Test class for BeanHelper. |
| */ |
| public class TestBeanHelper { |
| |
| /** |
| * An implementation of the BeanFactory interface used for testing. This implementation is really simple: If the |
| * BeanCreationTestBean class is provided, a new instance will be created. Otherwise an exception is thrown. |
| */ |
| private final class TestBeanFactory implements BeanFactory { |
| |
| private Object parameter; |
| |
| private boolean supportsDefaultClass; |
| |
| /** A counter for the created instances. */ |
| private int createBeanCount; |
| |
| @Override |
| public Object createBean(final BeanCreationContext bcc) { |
| createBeanCount++; |
| parameter = bcc.getParameter(); |
| if (BeanCreationTestBean.class.equals(bcc.getBeanClass())) { |
| final BeanCreationTestBean bean = new BeanCreationTestBean(); |
| helper.initBean(bean, bcc.getBeanDeclaration()); |
| return bean; |
| } |
| if (BeanCreationTestBeanWithListChild.class.equals(bcc.getBeanClass())) { |
| final BeanCreationTestBeanWithListChild bean = new BeanCreationTestBeanWithListChild(); |
| helper.initBean(bean, bcc.getBeanDeclaration()); |
| return bean; |
| } |
| throw new IllegalArgumentException("Unsupported class: " + bcc.getBeanClass()); |
| } |
| |
| /** |
| * Returns the number of beans created via this factory. |
| * |
| * @return the number of created beans |
| */ |
| public int getCreateBeanCount() { |
| return createBeanCount; |
| } |
| |
| /** |
| * Returns the default class, but only if the supportsDefaultClass flag is set. |
| */ |
| @Override |
| public Class<?> getDefaultBeanClass() { |
| return supportsDefaultClass ? BeanCreationTestBean.class : null; |
| } |
| } |
| |
| /** 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"; |
| |
| /** The test bean helper instance. */ |
| private BeanHelper helper; |
| |
| /** |
| * 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(final BeanCreationTestBean bean) { |
| assertEquals(TEST_STRING, bean.getStringValue()); |
| assertEquals(TEST_INT, bean.getIntValue()); |
| final BeanCreationTestBean buddy = bean.getBuddy(); |
| assertNotNull(buddy); |
| assertEquals("Another test string", buddy.getStringValue()); |
| assertEquals(100, buddy.getIntValue()); |
| } |
| |
| /** |
| * 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(final BeanCreationTestBeanWithListChild bean) { |
| assertEquals(TEST_STRING, bean.getStringValue()); |
| assertEquals(TEST_INT, bean.getIntValue()); |
| final List<BeanCreationTestBean> children = bean.getChildren(); |
| assertNotNull(children); |
| assertEquals(2, children.size()); |
| assertNotNull(children.get(0)); |
| assertNotNull(children.get(1)); |
| } |
| |
| /** |
| * 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 BeanDeclarationTestImpl createChildBean(final String name) { |
| final BeanDeclarationTestImpl childBean = new BeanDeclarationTestImpl(); |
| final Map<String, Object> properties2 = new HashMap<>(); |
| properties2.put("stringValue", name + " Another test string"); |
| properties2.put("intValue", 100); |
| childBean.setBeanProperties(properties2); |
| childBean.setBeanClassName(BeanCreationTestBean.class.getName()); |
| |
| return childBean; |
| } |
| |
| @BeforeEach |
| public void setUp() throws Exception { |
| helper = new BeanHelper(new TestBeanFactory()); |
| } |
| |
| /** |
| * Returns an initialized bean declaration. |
| * |
| * @return the bean declaration |
| */ |
| private BeanDeclarationTestImpl setUpBeanDeclaration() { |
| final BeanDeclarationTestImpl data = new BeanDeclarationTestImpl(); |
| final Map<String, Object> properties = new HashMap<>(); |
| properties.put("stringValue", TEST_STRING); |
| properties.put("intValue", String.valueOf(TEST_INT)); |
| data.setBeanProperties(properties); |
| final BeanDeclarationTestImpl buddyData = new BeanDeclarationTestImpl(); |
| final Map<String, Object> properties2 = new HashMap<>(); |
| properties2.put("stringValue", "Another test string"); |
| properties2.put("intValue", 100); |
| buddyData.setBeanProperties(properties2); |
| buddyData.setBeanClassName(BeanCreationTestBean.class.getName()); |
| |
| final Map<String, Object> nested = new HashMap<>(); |
| nested.put("buddy", buddyData); |
| data.setNestedBeanDeclarations(nested); |
| return data; |
| } |
| |
| /** |
| * 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 BeanDeclarationTestImpl setUpBeanDeclarationWithListChild() { |
| final BeanDeclarationTestImpl data = new BeanDeclarationTestImpl(); |
| final Map<String, Object> properties = new HashMap<>(); |
| properties.put("stringValue", TEST_STRING); |
| properties.put("intValue", String.valueOf(TEST_INT)); |
| data.setBeanProperties(properties); |
| |
| final List<BeanDeclaration> childData = new ArrayList<>(); |
| childData.add(createChildBean("child1")); |
| childData.add(createChildBean("child2")); |
| final Map<String, Object> nested = new HashMap<>(); |
| nested.put("children", childData); |
| data.setNestedBeanDeclarations(nested); |
| return data; |
| } |
| |
| /** |
| * Tests whether properties from one bean to another can be copied. |
| */ |
| @Test |
| void testCopyProperties() throws Exception { |
| final PropertiesConfiguration src = new PropertiesConfiguration(); |
| src.setHeader("TestHeader"); |
| src.setFooter("TestFooter"); |
| final LazyDynaBean dest = new LazyDynaBean(); |
| BeanHelper.copyProperties(dest, src); |
| assertEquals("TestFooter", dest.get("footer")); |
| assertEquals("TestHeader", dest.get("header")); |
| } |
| |
| /** |
| * Tests creating a bean. All necessary information is stored in the bean declaration. |
| */ |
| @Test |
| void testCreateBean() { |
| final TestBeanFactory factory = new TestBeanFactory(); |
| helper.registerBeanFactory(TEST_FACTORY, factory); |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| data.setBeanClassName(BeanCreationTestBean.class.getName()); |
| checkBean((BeanCreationTestBean) helper.createBean(data, null)); |
| assertNull(factory.parameter); |
| assertEquals(1, factory.getCreateBeanCount()); |
| } |
| |
| /** |
| * Tests creating a bean. The bean's class is specified as the default class argument. |
| */ |
| @Test |
| void testCreateBeanWithDefaultClass() { |
| helper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| checkBean((BeanCreationTestBean) helper.createBean(data, BeanCreationTestBean.class)); |
| } |
| |
| /** |
| * Tests creating a bean using the default bean factory. |
| */ |
| @Test |
| void testCreateBeanWithDefaultFactory() { |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanClassName(BeanCreationTestBean.class.getName()); |
| checkBean((BeanCreationTestBean) helper.createBean(data, null)); |
| final TestBeanFactory factory = (TestBeanFactory) helper.getDefaultBeanFactory(); |
| assertTrue(factory.getCreateBeanCount() > 0); |
| } |
| |
| /** |
| * Tests creating a bean when the factory throws an exception. |
| */ |
| @Test |
| void testCreateBeanWithException() { |
| helper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| data.setBeanClassName(getClass().getName()); |
| assertThrows(ConfigurationRuntimeException.class, () -> helper.createBean(data, null)); |
| } |
| |
| /** |
| * Tests creating a bean when the bean's class is specified as the default class of the bean factory. |
| */ |
| @Test |
| void testCreateBeanWithFactoryDefaultClass() { |
| final TestBeanFactory factory = new TestBeanFactory(); |
| factory.supportsDefaultClass = true; |
| helper.registerBeanFactory(TEST_FACTORY, factory); |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| checkBean((BeanCreationTestBean) helper.createBean(data, null)); |
| assertEquals(1, factory.getCreateBeanCount()); |
| } |
| |
| /** |
| * Tries to create a bean with a non existing class. This should cause an exception. |
| */ |
| @Test |
| void testCreateBeanWithInvalidClass() { |
| helper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| data.setBeanClassName("non.existing.ClassName"); |
| assertThrows(ConfigurationRuntimeException.class, () -> helper.createBean(data, null)); |
| } |
| |
| /** |
| * Tests whether a bean with a property of type collection can be created. |
| */ |
| @Test |
| void testCreateBeanWithListChildBean() { |
| final TestBeanFactory factory = new TestBeanFactory(); |
| helper.registerBeanFactory(TEST_FACTORY, factory); |
| final BeanDeclarationTestImpl data = setUpBeanDeclarationWithListChild(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| data.setBeanClassName(BeanCreationTestBeanWithListChild.class.getName()); |
| checkBean((BeanCreationTestBeanWithListChild) helper.createBean(data, null)); |
| assertNull(factory.parameter); |
| assertEquals(1, factory.getCreateBeanCount()); |
| } |
| |
| /** |
| * Tries to create a bean if no class is provided. This should cause an exception. |
| */ |
| @Test |
| void testCreateBeanWithNoClass() { |
| helper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| assertThrows(ConfigurationRuntimeException.class, () -> helper.createBean(data, null)); |
| } |
| |
| /** |
| * Tests creating a bean when no bean declaration is provided. This should cause an exception. |
| */ |
| @Test |
| void testCreateBeanWithNullDeclaration() { |
| assertThrows(IllegalArgumentException.class, () -> helper.createBean(null)); |
| } |
| |
| /** |
| * Tests if a parameter is correctly passed to the bean factory. |
| */ |
| @Test |
| void testCreateBeanWithParameter() { |
| final Object param = 42; |
| final TestBeanFactory factory = new TestBeanFactory(); |
| helper.registerBeanFactory(TEST_FACTORY, factory); |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| data.setBeanClassName(BeanCreationTestBean.class.getName()); |
| checkBean((BeanCreationTestBean) helper.createBean(data, null, param)); |
| assertSame(param, factory.parameter); |
| } |
| |
| /** |
| * Tests creating a bean using a non registered factory. |
| */ |
| @Test |
| void testCreateBeanWithUnknownFactory() { |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.setBeanFactoryName(TEST_FACTORY); |
| data.setBeanClassName(BeanCreationTestBean.class.getName()); |
| assertThrows(ConfigurationRuntimeException.class, () -> helper.createBean(data, null)); |
| } |
| |
| /** |
| * Tests whether a wrapper DynaBean for a Java bean can be created. |
| */ |
| @Test |
| void testCreateWrapDynaBean() { |
| final PropertiesConfiguration config = new PropertiesConfiguration(); |
| final DynaBean bean = BeanHelper.createWrapDynaBean(config); |
| final String value = "TestFooter"; |
| bean.set("footer", value); |
| assertEquals(value, config.getFooter()); |
| } |
| |
| /** |
| * Tries to create a wrapper DynaBean for a null bean. |
| */ |
| @Test |
| void testCreateWrapDynaBeanNull() { |
| assertThrows(IllegalArgumentException.class, () -> BeanHelper.createWrapDynaBean(null)); |
| } |
| |
| /** |
| * Tests whether the correct default bean factory is set. |
| */ |
| @Test |
| void testDefaultBeanFactory() { |
| helper = new BeanHelper(); |
| assertSame(DefaultBeanFactory.INSTANCE, helper.getDefaultBeanFactory()); |
| } |
| |
| /** |
| * Tests the default instance of BeanHelper. |
| */ |
| @Test |
| void testDefaultInstance() { |
| assertSame(DefaultBeanFactory.INSTANCE, BeanHelper.INSTANCE.getDefaultBeanFactory()); |
| } |
| |
| /** |
| * Tests to deregister a bean factory. |
| */ |
| @Test |
| void testDeregisterBeanFactory() { |
| final BeanFactory factory = new TestBeanFactory(); |
| helper.registerBeanFactory(TEST_FACTORY, factory); |
| assertSame(factory, helper.deregisterBeanFactory(TEST_FACTORY)); |
| assertEquals(Collections.emptySet(), helper.registeredFactoryNames()); |
| } |
| |
| /** |
| * Tests deregisterBeanFactory() for a non-existing factory name. |
| */ |
| @Test |
| void testDeregisterBeanFactoryNonExisting() { |
| assertNull(helper.deregisterBeanFactory(TEST_FACTORY)); |
| } |
| |
| /** |
| * Tests deregisterBeanFactory() for a null factory name. |
| */ |
| @Test |
| void testDeregisterBeanFactoryNull() { |
| assertNull(helper.deregisterBeanFactory(null)); |
| } |
| |
| /** |
| * Tests initializing a bean. |
| */ |
| @Test |
| void testInitBean() { |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| final BeanCreationTestBean bean = new BeanCreationTestBean(); |
| helper.initBean(bean, data); |
| checkBean(bean); |
| } |
| |
| /** |
| * Tries to initialize a bean with a bean declaration that contains an invalid property value. This should cause an |
| * exception. |
| */ |
| @Test |
| void testInitBeanWithInvalidProperty() { |
| final BeanDeclarationTestImpl data = setUpBeanDeclaration(); |
| data.getBeanProperties().put("nonExistingProperty", Boolean.TRUE); |
| final BeanCreationTestBean bean = new BeanCreationTestBean(); |
| assertThrows(ConfigurationRuntimeException.class, () -> helper.initBean(bean, data)); |
| } |
| |
| /** |
| * Tests initializing a bean when the bean declaration does not contain any data. |
| */ |
| @Test |
| void testInitBeanWithNoData() { |
| final BeanDeclarationTestImpl data = new BeanDeclarationTestImpl(); |
| final BeanCreationTestBean bean = new BeanCreationTestBean(); |
| helper.initBean(bean, data); |
| assertNull(bean.getStringValue()); |
| assertEquals(0, bean.getIntValue()); |
| assertNull(bean.getBuddy()); |
| } |
| |
| /** |
| * Tests whether a specific default bean factory can be set when constructing an instance. |
| */ |
| @Test |
| void testInitWithBeanFactory() { |
| final BeanFactory factory = mock(BeanFactory.class); |
| helper = new BeanHelper(factory); |
| assertSame(factory, helper.getDefaultBeanFactory()); |
| } |
| |
| /** |
| * Tests registering a new bean factory. |
| */ |
| @Test |
| void testRegisterBeanFactory() { |
| helper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); |
| assertEquals(Collections.singleton(TEST_FACTORY), helper.registeredFactoryNames()); |
| } |
| |
| /** |
| * Tries to register a null factory. This should cause an exception. |
| */ |
| @Test |
| void testRegisterBeanFactoryNull() { |
| assertThrows(IllegalArgumentException.class, () -> helper.registerBeanFactory(TEST_FACTORY, null)); |
| } |
| |
| /** |
| * Tries to register a bean factory with a null name. This should cause an exception. |
| */ |
| @Test |
| void testRegisterBeanFactoryNullName() { |
| final BeanFactory beanFactory = new TestBeanFactory(); |
| assertThrows(IllegalArgumentException.class, () -> helper.registerBeanFactory(null, beanFactory)); |
| } |
| |
| /** |
| * Tests that a newly created instance does not have any bean factories registered. |
| */ |
| @Test |
| void testRegisteredFactoriesEmptyForNewInstance() { |
| assertEquals(Collections.emptySet(), helper.registeredFactoryNames()); |
| } |
| } |