org.springframework.beans.factory.xml.XmlBeanFactoryTests.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.beans.factory.xml.XmlBeanFactoryTests.java

Source

/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed 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.springframework.beans.factory.xml;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.xml.sax.InputSource;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanIsAbstractException;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.MethodReplacer;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.UrlResource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.tests.sample.beans.DependenciesBean;
import org.springframework.tests.sample.beans.DerivedTestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.IndexedTestBean;
import org.springframework.tests.sample.beans.ResourceTestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.tests.sample.beans.factory.DummyFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.SerializationTestUtils;
import org.springframework.util.StopWatch;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

/**
 * Miscellaneous tests for XML bean definitions.
 *
 * @author Juergen Hoeller
 * @author Rod Johnson
 * @author Rick Evans
 * @author Chris Beams
 * @author Sam Brannen
 */
public class XmlBeanFactoryTests {

    private static final Class<?> CLASS = XmlBeanFactoryTests.class;
    private static final String CLASSNAME = CLASS.getSimpleName();

    private static final ClassPathResource AUTOWIRE_CONTEXT = classPathResource("-autowire.xml");
    private static final ClassPathResource CHILD_CONTEXT = classPathResource("-child.xml");
    private static final ClassPathResource CLASS_NOT_FOUND_CONTEXT = classPathResource("-classNotFound.xml");
    private static final ClassPathResource COMPLEX_FACTORY_CIRCLE_CONTEXT = classPathResource(
            "-complexFactoryCircle.xml");
    private static final ClassPathResource CONSTRUCTOR_ARG_CONTEXT = classPathResource("-constructorArg.xml");
    private static final ClassPathResource CONSTRUCTOR_OVERRIDES_CONTEXT = classPathResource(
            "-constructorOverrides.xml");
    private static final ClassPathResource DELEGATION_OVERRIDES_CONTEXT = classPathResource(
            "-delegationOverrides.xml");
    private static final ClassPathResource DEP_CARG_AUTOWIRE_CONTEXT = classPathResource("-depCargAutowire.xml");
    private static final ClassPathResource DEP_CARG_INNER_CONTEXT = classPathResource("-depCargInner.xml");
    private static final ClassPathResource DEP_CARG_CONTEXT = classPathResource("-depCarg.xml");
    private static final ClassPathResource DEP_DEPENDSON_INNER_CONTEXT = classPathResource(
            "-depDependsOnInner.xml");
    private static final ClassPathResource DEP_DEPENDSON_CONTEXT = classPathResource("-depDependsOn.xml");
    private static final ClassPathResource DEP_PROP = classPathResource("-depProp.xml");
    private static final ClassPathResource DEP_PROP_ABN_CONTEXT = classPathResource("-depPropAutowireByName.xml");
    private static final ClassPathResource DEP_PROP_ABT_CONTEXT = classPathResource("-depPropAutowireByType.xml");
    private static final ClassPathResource DEP_PROP_MIDDLE_CONTEXT = classPathResource("-depPropInTheMiddle.xml");
    private static final ClassPathResource DEP_PROP_INNER_CONTEXT = classPathResource("-depPropInner.xml");
    private static final ClassPathResource DEP_MATERIALIZE_CONTEXT = classPathResource("-depMaterializeThis.xml");
    private static final ClassPathResource FACTORY_CIRCLE_CONTEXT = classPathResource("-factoryCircle.xml");
    private static final ClassPathResource INITIALIZERS_CONTEXT = classPathResource("-initializers.xml");
    private static final ClassPathResource INVALID_CONTEXT = classPathResource("-invalid.xml");
    private static final ClassPathResource INVALID_NO_SUCH_METHOD_CONTEXT = classPathResource(
            "-invalidOverridesNoSuchMethod.xml");
    private static final ClassPathResource COLLECTIONS_XSD_CONTEXT = classPathResource(
            "-localCollectionsUsingXsd.xml");
    private static final ClassPathResource MISSING_CONTEXT = classPathResource("-missing.xml");
    private static final ClassPathResource OVERRIDES_CONTEXT = classPathResource("-overrides.xml");
    private static final ClassPathResource PARENT_CONTEXT = classPathResource("-parent.xml");
    private static final ClassPathResource NO_SUCH_FACTORY_METHOD_CONTEXT = classPathResource(
            "-noSuchFactoryMethod.xml");
    private static final ClassPathResource RECURSIVE_IMPORT_CONTEXT = classPathResource("-recursiveImport.xml");
    private static final ClassPathResource RESOURCE_CONTEXT = classPathResource("-resource.xml");
    private static final ClassPathResource TEST_WITH_DUP_NAMES_CONTEXT = classPathResource(
            "-testWithDuplicateNames.xml");
    private static final ClassPathResource TEST_WITH_DUP_NAME_IN_ALIAS_CONTEXT = classPathResource(
            "-testWithDuplicateNameInAlias.xml");
    private static final ClassPathResource REFTYPES_CONTEXT = classPathResource("-reftypes.xml");
    private static final ClassPathResource DEFAULT_LAZY_CONTEXT = classPathResource("-defaultLazyInit.xml");
    private static final ClassPathResource DEFAULT_AUTOWIRE_CONTEXT = classPathResource("-defaultAutowire.xml");

    private static ClassPathResource classPathResource(String suffix) {
        return new ClassPathResource(CLASSNAME + suffix, CLASS);
    }

    /* SPR-2368 */
    @Test
    public void testCollectionsReferredToAsRefLocals() throws Exception {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(factory).loadBeanDefinitions(COLLECTIONS_XSD_CONTEXT);
        factory.preInstantiateSingletons();
    }

    @Test
    public void testRefToSeparatePrototypeInstances() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);

        TestBean emma = (TestBean) xbf.getBean("emma");
        TestBean georgia = (TestBean) xbf.getBean("georgia");
        ITestBean emmasJenks = emma.getSpouse();
        ITestBean georgiasJenks = georgia.getSpouse();
        assertTrue("Emma and georgia think they have a different boyfriend", emmasJenks != georgiasJenks);
        assertTrue("Emmas jenks has right name", emmasJenks.getName().equals("Andrew"));
        assertTrue("Emmas doesn't equal new ref", emmasJenks != xbf.getBean("jenks"));
        assertTrue("Georgias jenks has right name", emmasJenks.getName().equals("Andrew"));
        assertTrue("They are object equal", emmasJenks.equals(georgiasJenks));
        assertTrue("They object equal direct ref", emmasJenks.equals(xbf.getBean("jenks")));
    }

    @Test
    public void testRefToSingleton() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(new EncodedResource(REFTYPES_CONTEXT, "ISO-8859-1"));

        TestBean jen = (TestBean) xbf.getBean("jenny");
        TestBean dave = (TestBean) xbf.getBean("david");
        TestBean jenks = (TestBean) xbf.getBean("jenks");
        ITestBean davesJen = dave.getSpouse();
        ITestBean jenksJen = jenks.getSpouse();
        assertTrue("1 jen instance", davesJen == jenksJen);
        assertTrue("1 jen instance", davesJen == jen);
    }

    @Test
    public void testInnerBeans() throws IOException {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);

        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        InputStream inputStream = getClass().getResourceAsStream(REFTYPES_CONTEXT.getPath());
        try {
            reader.loadBeanDefinitions(new InputSource(inputStream));
        } finally {
            inputStream.close();
        }

        // Let's create the outer bean named "innerBean",
        // to check whether it doesn't create any conflicts
        // with the actual inner beans named "innerBean".
        xbf.getBean("innerBean");

        TestBean hasInnerBeans = (TestBean) xbf.getBean("hasInnerBeans");
        assertEquals(5, hasInnerBeans.getAge());
        TestBean inner1 = (TestBean) hasInnerBeans.getSpouse();
        assertNotNull(inner1);
        assertEquals("innerBean#1", inner1.getBeanName());
        assertEquals("inner1", inner1.getName());
        assertEquals(6, inner1.getAge());

        assertNotNull(hasInnerBeans.getFriends());
        Object[] friends = hasInnerBeans.getFriends().toArray();
        assertEquals(3, friends.length);
        DerivedTestBean inner2 = (DerivedTestBean) friends[0];
        assertEquals("inner2", inner2.getName());
        assertTrue(inner2.getBeanName().startsWith(DerivedTestBean.class.getName()));
        assertFalse(xbf.containsBean("innerBean#1"));
        assertNotNull(inner2);
        assertEquals(7, inner2.getAge());
        TestBean innerFactory = (TestBean) friends[1];
        assertEquals(DummyFactory.SINGLETON_NAME, innerFactory.getName());
        TestBean inner5 = (TestBean) friends[2];
        assertEquals("innerBean#2", inner5.getBeanName());

        assertNotNull(hasInnerBeans.getSomeMap());
        assertEquals(2, hasInnerBeans.getSomeMap().size());
        TestBean inner3 = (TestBean) hasInnerBeans.getSomeMap().get("someKey");
        assertEquals("Jenny", inner3.getName());
        assertEquals(30, inner3.getAge());
        TestBean inner4 = (TestBean) hasInnerBeans.getSomeMap().get("someOtherKey");
        assertEquals("inner4", inner4.getName());
        assertEquals(9, inner4.getAge());

        TestBean hasInnerBeansForConstructor = (TestBean) xbf.getBean("hasInnerBeansForConstructor");
        TestBean innerForConstructor = (TestBean) hasInnerBeansForConstructor.getSpouse();
        assertNotNull(innerForConstructor);
        assertEquals("innerBean#3", innerForConstructor.getBeanName());
        assertEquals("inner1", innerForConstructor.getName());
        assertEquals(6, innerForConstructor.getAge());

        hasInnerBeansForConstructor = (TestBean) xbf.getBean("hasInnerBeansAsPrototype");
        innerForConstructor = (TestBean) hasInnerBeansForConstructor.getSpouse();
        assertNotNull(innerForConstructor);
        assertEquals("innerBean", innerForConstructor.getBeanName());
        assertEquals("inner1", innerForConstructor.getName());
        assertEquals(6, innerForConstructor.getAge());

        hasInnerBeansForConstructor = (TestBean) xbf.getBean("hasInnerBeansAsPrototype");
        innerForConstructor = (TestBean) hasInnerBeansForConstructor.getSpouse();
        assertNotNull(innerForConstructor);
        assertEquals("innerBean", innerForConstructor.getBeanName());
        assertEquals("inner1", innerForConstructor.getName());
        assertEquals(6, innerForConstructor.getAge());

        xbf.destroySingletons();
        assertTrue(inner1.wasDestroyed());
        assertTrue(inner2.wasDestroyed());
        assertTrue(innerFactory.getName() == null);
        assertTrue(inner5.wasDestroyed());
    }

    @Test
    public void testInnerBeansWithoutDestroy() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);

        // Let's create the outer bean named "innerBean",
        // to check whether it doesn't create any conflicts
        // with the actual inner beans named "innerBean".
        xbf.getBean("innerBean");

        TestBean hasInnerBeans = (TestBean) xbf.getBean("hasInnerBeansWithoutDestroy");
        assertEquals(5, hasInnerBeans.getAge());
        TestBean inner1 = (TestBean) hasInnerBeans.getSpouse();
        assertNotNull(inner1);
        assertTrue(inner1.getBeanName().startsWith("innerBean"));
        assertEquals("inner1", inner1.getName());
        assertEquals(6, inner1.getAge());

        assertNotNull(hasInnerBeans.getFriends());
        Object[] friends = hasInnerBeans.getFriends().toArray();
        assertEquals(3, friends.length);
        DerivedTestBean inner2 = (DerivedTestBean) friends[0];
        assertEquals("inner2", inner2.getName());
        assertTrue(inner2.getBeanName().startsWith(DerivedTestBean.class.getName()));
        assertNotNull(inner2);
        assertEquals(7, inner2.getAge());
        TestBean innerFactory = (TestBean) friends[1];
        assertEquals(DummyFactory.SINGLETON_NAME, innerFactory.getName());
        TestBean inner5 = (TestBean) friends[2];
        assertTrue(inner5.getBeanName().startsWith("innerBean"));
    }

    @Test
    public void testFailsOnInnerBean() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);

        try {
            xbf.getBean("failsOnInnerBean");
        } catch (BeanCreationException ex) {
            // Check whether message contains outer bean name.
            ex.printStackTrace();
            assertTrue(ex.getMessage().contains("failsOnInnerBean"));
            assertTrue(ex.getMessage().contains("someMap"));
        }

        try {
            xbf.getBean("failsOnInnerBeanForConstructor");
        } catch (BeanCreationException ex) {
            // Check whether message contains outer bean name.
            ex.printStackTrace();
            assertTrue(ex.getMessage().contains("failsOnInnerBeanForConstructor"));
            assertTrue(ex.getMessage().contains("constructor argument"));
        }
    }

    @Test
    public void testInheritanceFromParentFactoryPrototype() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        assertEquals(TestBean.class, child.getType("inheritsFromParentFactory"));
        TestBean inherits = (TestBean) child.getBean("inheritsFromParentFactory");
        // Name property value is overridden
        assertTrue(inherits.getName().equals("override"));
        // Age property is inherited from bean in parent factory
        assertTrue(inherits.getAge() == 1);
        TestBean inherits2 = (TestBean) child.getBean("inheritsFromParentFactory");
        assertFalse(inherits2 == inherits);
    }

    @Test
    public void testInheritanceWithDifferentClass() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        assertEquals(DerivedTestBean.class, child.getType("inheritsWithClass"));
        DerivedTestBean inherits = (DerivedTestBean) child.getBean("inheritsWithDifferentClass");
        // Name property value is overridden
        assertTrue(inherits.getName().equals("override"));
        // Age property is inherited from bean in parent factory
        assertTrue(inherits.getAge() == 1);
        assertTrue(inherits.wasInitialized());
    }

    @Test
    public void testInheritanceWithClass() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        assertEquals(DerivedTestBean.class, child.getType("inheritsWithClass"));
        DerivedTestBean inherits = (DerivedTestBean) child.getBean("inheritsWithClass");
        // Name property value is overridden
        assertTrue(inherits.getName().equals("override"));
        // Age property is inherited from bean in parent factory
        assertTrue(inherits.getAge() == 1);
        assertTrue(inherits.wasInitialized());
    }

    @Test
    public void testPrototypeInheritanceFromParentFactoryPrototype() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        assertEquals(TestBean.class, child.getType("prototypeInheritsFromParentFactoryPrototype"));
        TestBean inherits = (TestBean) child.getBean("prototypeInheritsFromParentFactoryPrototype");
        // Name property value is overridden
        assertTrue(inherits.getName().equals("prototype-override"));
        // Age property is inherited from bean in parent factory
        assertTrue(inherits.getAge() == 2);
        TestBean inherits2 = (TestBean) child.getBean("prototypeInheritsFromParentFactoryPrototype");
        assertFalse(inherits2 == inherits);
        inherits2.setAge(13);
        assertTrue(inherits2.getAge() == 13);
        // Shouldn't have changed first instance
        assertTrue(inherits.getAge() == 2);
    }

    @Test
    public void testPrototypeInheritanceFromParentFactorySingleton() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        TestBean inherits = (TestBean) child.getBean("protoypeInheritsFromParentFactorySingleton");
        // Name property value is overridden
        assertTrue(inherits.getName().equals("prototypeOverridesInheritedSingleton"));
        // Age property is inherited from bean in parent factory
        assertTrue(inherits.getAge() == 1);
        TestBean inherits2 = (TestBean) child.getBean("protoypeInheritsFromParentFactorySingleton");
        assertFalse(inherits2 == inherits);
        inherits2.setAge(13);
        assertTrue(inherits2.getAge() == 13);
        // Shouldn't have changed first instance
        assertTrue(inherits.getAge() == 1);
    }

    @Test
    public void testAutowireModeNotInherited() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(OVERRIDES_CONTEXT);

        TestBean david = (TestBean) xbf.getBean("magicDavid");
        // the parent bean is autowiring
        assertNotNull(david.getSpouse());

        TestBean derivedDavid = (TestBean) xbf.getBean("magicDavidDerived");
        // this fails while it inherits from the child bean
        assertNull("autowiring not propagated along child relationships", derivedDavid.getSpouse());
    }

    @Test
    public void testAbstractParentBeans() {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        parent.preInstantiateSingletons();
        assertTrue(parent.isSingleton("inheritedTestBeanWithoutClass"));

        // abstract beans should not match
        Map<?, ?> tbs = parent.getBeansOfType(TestBean.class);
        assertEquals(2, tbs.size());
        assertTrue(tbs.containsKey("inheritedTestBeanPrototype"));
        assertTrue(tbs.containsKey("inheritedTestBeanSingleton"));

        // abstract bean should throw exception on creation attempt
        try {
            parent.getBean("inheritedTestBeanWithoutClass");
            fail("Should have thrown BeanIsAbstractException");
        } catch (BeanIsAbstractException ex) {
            // expected
        }

        // non-abstract bean should work, even if it serves as parent
        assertTrue(parent.getBean("inheritedTestBeanPrototype") instanceof TestBean);
    }

    @Test
    public void testDependenciesMaterializeThis() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(DEP_MATERIALIZE_CONTEXT);

        assertEquals(2, xbf.getBeansOfType(DummyBo.class, true, false).size());
        assertEquals(3, xbf.getBeansOfType(DummyBo.class, true, true).size());
        assertEquals(3, xbf.getBeansOfType(DummyBo.class, true, false).size());
        assertEquals(3, xbf.getBeansOfType(DummyBo.class).size());
        assertEquals(2, xbf.getBeansOfType(DummyBoImpl.class, true, true).size());
        assertEquals(1, xbf.getBeansOfType(DummyBoImpl.class, false, true).size());
        assertEquals(2, xbf.getBeansOfType(DummyBoImpl.class).size());

        DummyBoImpl bos = (DummyBoImpl) xbf.getBean("boSingleton");
        DummyBoImpl bop = (DummyBoImpl) xbf.getBean("boPrototype");
        assertNotSame(bos, bop);
        assertTrue(bos.dao == bop.dao);
    }

    @Test
    public void testChildOverridesParentBean() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        TestBean inherits = (TestBean) child.getBean("inheritedTestBean");
        // Name property value is overridden
        assertTrue(inherits.getName().equals("overrideParentBean"));
        // Age property is inherited from bean in parent factory
        assertTrue(inherits.getAge() == 1);
        TestBean inherits2 = (TestBean) child.getBean("inheritedTestBean");
        assertTrue(inherits2 != inherits);
    }

    /**
     * Check that a prototype can't inherit from a bogus parent.
     * If a singleton does this the factory will fail to load.
     */
    @Test
    public void testBogusParentageFromParentFactory() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        try {
            child.getBean("bogusParent", TestBean.class);
            fail();
        } catch (BeanDefinitionStoreException ex) {
            // check exception message contains the name
            assertTrue(ex.getMessage().indexOf("bogusParent") != -1);
            assertTrue(ex.getCause() instanceof NoSuchBeanDefinitionException);
        }
    }

    /**
     * Note that prototype/singleton distinction is <b>not</b> inherited.
     * It's possible for a subclass singleton not to return independent
     * instances even if derived from a prototype
     */
    @Test
    public void testSingletonInheritsFromParentFactoryPrototype() throws Exception {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        TestBean inherits = (TestBean) child.getBean("singletonInheritsFromParentFactoryPrototype");
        // Name property value is overridden
        assertTrue(inherits.getName().equals("prototype-override"));
        // Age property is inherited from bean in parent factory
        assertTrue(inherits.getAge() == 2);
        TestBean inherits2 = (TestBean) child.getBean("singletonInheritsFromParentFactoryPrototype");
        assertTrue(inherits2 == inherits);
    }

    @Test
    public void testSingletonFromParent() {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        TestBean beanFromParent = (TestBean) parent.getBean("inheritedTestBeanSingleton");
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        TestBean beanFromChild = (TestBean) child.getBean("inheritedTestBeanSingleton");
        assertTrue("singleton from parent and child is the same", beanFromParent == beanFromChild);
    }

    @Test
    public void testNestedPropertyValue() {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(parent).loadBeanDefinitions(PARENT_CONTEXT);
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        new XmlBeanDefinitionReader(child).loadBeanDefinitions(CHILD_CONTEXT);
        IndexedTestBean bean = (IndexedTestBean) child.getBean("indexedTestBean");
        assertEquals("name applied correctly", "myname", bean.getArray()[0].getName());
    }

    @Test
    public void testCircularReferences() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);
        TestBean jenny = (TestBean) xbf.getBean("jenny");
        TestBean david = (TestBean) xbf.getBean("david");
        TestBean ego = (TestBean) xbf.getBean("ego");
        TestBean complexInnerEgo = (TestBean) xbf.getBean("complexInnerEgo");
        TestBean complexEgo = (TestBean) xbf.getBean("complexEgo");
        assertTrue("Correct circular reference", jenny.getSpouse() == david);
        assertTrue("Correct circular reference", david.getSpouse() == jenny);
        assertTrue("Correct circular reference", ego.getSpouse() == ego);
        assertTrue("Correct circular reference", complexInnerEgo.getSpouse().getSpouse() == complexInnerEgo);
        assertTrue("Correct circular reference", complexEgo.getSpouse().getSpouse() == complexEgo);
    }

    @Test
    public void testCircularReferenceWithFactoryBeanFirst() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);
        xbf.getBean("egoBridge");
        TestBean complexEgo = (TestBean) xbf.getBean("complexEgo");
        assertTrue("Correct circular reference", complexEgo.getSpouse().getSpouse() == complexEgo);
    }

    @Test
    public void testCircularReferenceWithTwoFactoryBeans() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);
        TestBean ego1 = (TestBean) xbf.getBean("ego1");
        assertTrue("Correct circular reference", ego1.getSpouse().getSpouse() == ego1);
        TestBean ego3 = (TestBean) xbf.getBean("ego3");
        assertTrue("Correct circular reference", ego3.getSpouse().getSpouse() == ego3);
    }

    @Test
    public void testCircularReferencesWithNotAllowed() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        xbf.setAllowCircularReferences(false);
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);
        try {
            xbf.getBean("jenny");
            fail("Should have thrown BeanCreationException");
        } catch (BeanCreationException ex) {
            assertTrue(ex.contains(BeanCurrentlyInCreationException.class));
        }
    }

    @Test
    public void testCircularReferencesWithWrapping() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);
        xbf.addBeanPostProcessor(new WrappingPostProcessor());
        try {
            xbf.getBean("jenny");
            fail("Should have thrown BeanCreationException");
        } catch (BeanCreationException ex) {
            assertTrue(ex.contains(BeanCurrentlyInCreationException.class));
        }
    }

    @Test
    public void testCircularReferencesWithWrappingAndRawInjectionAllowed() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        xbf.setAllowRawInjectionDespiteWrapping(true);
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
        reader.loadBeanDefinitions(REFTYPES_CONTEXT);
        xbf.addBeanPostProcessor(new WrappingPostProcessor());

        ITestBean jenny = (ITestBean) xbf.getBean("jenny");
        ITestBean david = (ITestBean) xbf.getBean("david");
        assertTrue(AopUtils.isAopProxy(jenny));
        assertTrue(AopUtils.isAopProxy(david));
        assertSame(david, jenny.getSpouse());
        assertNotSame(jenny, david.getSpouse());
        assertEquals("Jenny", david.getSpouse().getName());
        assertSame(david, david.getSpouse().getSpouse());
        assertTrue(AopUtils.isAopProxy(jenny.getSpouse()));
        assertTrue(!AopUtils.isAopProxy(david.getSpouse()));
    }

    @Test
    public void testFactoryReferenceCircle() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(FACTORY_CIRCLE_CONTEXT);
        TestBean tb = (TestBean) xbf.getBean("singletonFactory");
        DummyFactory db = (DummyFactory) xbf.getBean("&singletonFactory");
        assertTrue(tb == db.getOtherTestBean());
    }

    @Test
    public void testFactoryReferenceWithDoublePrefix() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(FACTORY_CIRCLE_CONTEXT);
        assertThat(xbf.getBean("&&singletonFactory"), instanceOf(DummyFactory.class));
    }

    @Test
    public void testComplexFactoryReferenceCircle() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(COMPLEX_FACTORY_CIRCLE_CONTEXT);
        xbf.getBean("proxy1");
        // check that unused instances from autowiring got removed
        assertEquals(4, xbf.getSingletonCount());
        // properly create the remaining two instances
        xbf.getBean("proxy2");
        assertEquals(5, xbf.getSingletonCount());
    }

    @Test(expected = BeanCreationException.class)
    public void noSuchFactoryBeanMethod() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(NO_SUCH_FACTORY_METHOD_CONTEXT);
        assertNotNull(xbf.getBean("defaultTestBean"));
    }

    @Test
    public void testInitMethodIsInvoked() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(INITIALIZERS_CONTEXT);
        DoubleInitializer in = (DoubleInitializer) xbf.getBean("init-method1");
        // Initializer should have doubled value
        assertEquals(14, in.getNum());
    }

    /**
     * Test that if a custom initializer throws an exception, it's handled correctly
     */
    @Test
    public void testInitMethodThrowsException() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(INITIALIZERS_CONTEXT);
        try {
            xbf.getBean("init-method2");
            fail();
        } catch (BeanCreationException ex) {
            assertTrue(ex.getResourceDescription().indexOf("initializers.xml") != -1);
            assertEquals("init-method2", ex.getBeanName());
            assertTrue(ex.getCause() instanceof IOException);
        }
    }

    @Test
    public void testNoSuchInitMethod() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(INITIALIZERS_CONTEXT);
        try {
            xbf.getBean("init-method3");
            fail();
        } catch (FatalBeanException ex) {
            // check message is helpful
            assertTrue(ex.getMessage().indexOf("initializers.xml") != -1);
            assertTrue(ex.getMessage().indexOf("init-method3") != -1);
            assertTrue(ex.getMessage().indexOf("init") != -1);
        }
    }

    /**
     * Check that InitializingBean method is called first.
     */
    @Test
    public void testInitializingBeanAndInitMethod() throws Exception {
        InitAndIB.constructed = false;
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(INITIALIZERS_CONTEXT);
        assertFalse(InitAndIB.constructed);
        xbf.preInstantiateSingletons();
        assertFalse(InitAndIB.constructed);
        InitAndIB iib = (InitAndIB) xbf.getBean("init-and-ib");
        assertTrue(InitAndIB.constructed);
        assertTrue(iib.afterPropertiesSetInvoked && iib.initMethodInvoked);
        assertTrue(!iib.destroyed && !iib.customDestroyed);
        xbf.destroySingletons();
        assertTrue(iib.destroyed && iib.customDestroyed);
        xbf.destroySingletons();
        assertTrue(iib.destroyed && iib.customDestroyed);
    }

    /**
     * Check that InitializingBean method is not called twice.
     */
    @Test
    public void testInitializingBeanAndSameInitMethod() throws Exception {
        InitAndIB.constructed = false;
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(INITIALIZERS_CONTEXT);
        assertFalse(InitAndIB.constructed);
        xbf.preInstantiateSingletons();
        assertFalse(InitAndIB.constructed);
        InitAndIB iib = (InitAndIB) xbf.getBean("ib-same-init");
        assertTrue(InitAndIB.constructed);
        assertTrue(iib.afterPropertiesSetInvoked && !iib.initMethodInvoked);
        assertTrue(!iib.destroyed && !iib.customDestroyed);
        xbf.destroySingletons();
        assertTrue(iib.destroyed && !iib.customDestroyed);
        xbf.destroySingletons();
        assertTrue(iib.destroyed && !iib.customDestroyed);
    }

    @Test
    public void testDefaultLazyInit() throws Exception {
        InitAndIB.constructed = false;
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(DEFAULT_LAZY_CONTEXT);
        assertFalse(InitAndIB.constructed);
        xbf.preInstantiateSingletons();
        assertTrue(InitAndIB.constructed);
        try {
            xbf.getBean("lazy-and-bad");
        } catch (BeanCreationException ex) {
            assertTrue(ex.getCause() instanceof IOException);
        }
    }

    @Test(expected = BeanDefinitionStoreException.class)
    public void noSuchXmlFile() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(MISSING_CONTEXT);
    }

    @Test(expected = BeanDefinitionStoreException.class)
    public void invalidXmlFile() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(INVALID_CONTEXT);
    }

    @Test
    public void testAutowire() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(AUTOWIRE_CONTEXT);
        TestBean spouse = new TestBean("kerry", 0);
        xbf.registerSingleton("spouse", spouse);
        doTestAutowire(xbf);
    }

    @Test
    public void testAutowireWithParent() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(AUTOWIRE_CONTEXT);
        DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
        MutablePropertyValues pvs = new MutablePropertyValues();
        pvs.add("name", "kerry");
        RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
        bd.setPropertyValues(pvs);
        lbf.registerBeanDefinition("spouse", bd);
        xbf.setParentBeanFactory(lbf);
        doTestAutowire(xbf);
    }

    private void doTestAutowire(DefaultListableBeanFactory xbf) throws Exception {
        DependenciesBean rod1 = (DependenciesBean) xbf.getBean("rod1");
        TestBean kerry = (TestBean) xbf.getBean("spouse");
        // should have been autowired
        assertEquals(kerry, rod1.getSpouse());

        DependenciesBean rod1a = (DependenciesBean) xbf.getBean("rod1a");
        // should have been autowired
        assertEquals(kerry, rod1a.getSpouse());

        DependenciesBean rod2 = (DependenciesBean) xbf.getBean("rod2");
        // should have been autowired
        assertEquals(kerry, rod2.getSpouse());

        DependenciesBean rod2a = (DependenciesBean) xbf.getBean("rod2a");
        // should have been set explicitly
        assertEquals(kerry, rod2a.getSpouse());

        ConstructorDependenciesBean rod3 = (ConstructorDependenciesBean) xbf.getBean("rod3");
        IndexedTestBean other = (IndexedTestBean) xbf.getBean("other");
        // should have been autowired
        assertEquals(kerry, rod3.getSpouse1());
        assertEquals(kerry, rod3.getSpouse2());
        assertEquals(other, rod3.getOther());

        ConstructorDependenciesBean rod3a = (ConstructorDependenciesBean) xbf.getBean("rod3a");
        // should have been autowired
        assertEquals(kerry, rod3a.getSpouse1());
        assertEquals(kerry, rod3a.getSpouse2());
        assertEquals(other, rod3a.getOther());

        try {
            xbf.getBean("rod4", ConstructorDependenciesBean.class);
            fail("Must have thrown a FatalBeanException");
        } catch (FatalBeanException expected) {
            // expected
        }

        DependenciesBean rod5 = (DependenciesBean) xbf.getBean("rod5");
        // Should not have been autowired
        assertNull(rod5.getSpouse());

        BeanFactory appCtx = (BeanFactory) xbf.getBean("childAppCtx");
        assertTrue(appCtx.containsBean("rod1"));
        assertTrue(appCtx.containsBean("jenny"));
    }

    @Test
    public void testAutowireWithDefault() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(DEFAULT_AUTOWIRE_CONTEXT);

        DependenciesBean rod1 = (DependenciesBean) xbf.getBean("rod1");
        // should have been autowired
        assertNotNull(rod1.getSpouse());
        assertTrue(rod1.getSpouse().getName().equals("Kerry"));

        DependenciesBean rod2 = (DependenciesBean) xbf.getBean("rod2");
        // should have been autowired
        assertNotNull(rod2.getSpouse());
        assertTrue(rod2.getSpouse().getName().equals("Kerry"));
    }

    @Test
    public void testAutowireByConstructor() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        ConstructorDependenciesBean rod1 = (ConstructorDependenciesBean) xbf.getBean("rod1");
        TestBean kerry = (TestBean) xbf.getBean("kerry2");
        // should have been autowired
        assertEquals(kerry, rod1.getSpouse1());
        assertEquals(0, rod1.getAge());
        assertEquals(null, rod1.getName());

        ConstructorDependenciesBean rod2 = (ConstructorDependenciesBean) xbf.getBean("rod2");
        TestBean kerry1 = (TestBean) xbf.getBean("kerry1");
        TestBean kerry2 = (TestBean) xbf.getBean("kerry2");
        // should have been autowired
        assertEquals(kerry2, rod2.getSpouse1());
        assertEquals(kerry1, rod2.getSpouse2());
        assertEquals(0, rod2.getAge());
        assertEquals(null, rod2.getName());

        ConstructorDependenciesBean rod = (ConstructorDependenciesBean) xbf.getBean("rod3");
        IndexedTestBean other = (IndexedTestBean) xbf.getBean("other");
        // should have been autowired
        assertEquals(kerry, rod.getSpouse1());
        assertEquals(kerry, rod.getSpouse2());
        assertEquals(other, rod.getOther());
        assertEquals(0, rod.getAge());
        assertEquals(null, rod.getName());

        xbf.getBean("rod4", ConstructorDependenciesBean.class);
        // should have been autowired
        assertEquals(kerry, rod.getSpouse1());
        assertEquals(kerry, rod.getSpouse2());
        assertEquals(other, rod.getOther());
        assertEquals(0, rod.getAge());
        assertEquals(null, rod.getName());
    }

    @Test
    public void testAutowireByConstructorWithSimpleValues() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);

        ConstructorDependenciesBean rod5 = (ConstructorDependenciesBean) xbf.getBean("rod5");
        TestBean kerry1 = (TestBean) xbf.getBean("kerry1");
        TestBean kerry2 = (TestBean) xbf.getBean("kerry2");
        IndexedTestBean other = (IndexedTestBean) xbf.getBean("other");
        // should have been autowired
        assertEquals(kerry2, rod5.getSpouse1());
        assertEquals(kerry1, rod5.getSpouse2());
        assertEquals(other, rod5.getOther());
        assertEquals(99, rod5.getAge());
        assertEquals("myname", rod5.getName());

        DerivedConstructorDependenciesBean rod6 = (DerivedConstructorDependenciesBean) xbf.getBean("rod6");
        // should have been autowired
        assertTrue(rod6.initialized);
        assertTrue(!rod6.destroyed);
        assertEquals(kerry2, rod6.getSpouse1());
        assertEquals(kerry1, rod6.getSpouse2());
        assertEquals(other, rod6.getOther());
        assertEquals(0, rod6.getAge());
        assertEquals(null, rod6.getName());

        xbf.destroySingletons();
        assertTrue(rod6.destroyed);
    }

    @Test
    public void testRelatedCausesFromConstructorResolution() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);

        try {
            xbf.getBean("rod2Accessor");
        } catch (BeanCreationException ex) {
            assertTrue(ex.toString().indexOf("touchy") != -1);
            ex.printStackTrace();
            assertNull(ex.getRelatedCauses());
        }
    }

    @Test
    public void testConstructorArgResolution() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        TestBean kerry1 = (TestBean) xbf.getBean("kerry1");
        TestBean kerry2 = (TestBean) xbf.getBean("kerry2");

        ConstructorDependenciesBean rod9 = (ConstructorDependenciesBean) xbf.getBean("rod9");
        assertEquals(99, rod9.getAge());
        ConstructorDependenciesBean rod9a = (ConstructorDependenciesBean) xbf.getBean("rod9", 98);
        assertEquals(98, rod9a.getAge());
        ConstructorDependenciesBean rod9b = (ConstructorDependenciesBean) xbf.getBean("rod9", "myName");
        assertEquals("myName", rod9b.getName());
        ConstructorDependenciesBean rod9c = (ConstructorDependenciesBean) xbf.getBean("rod9", 97);
        assertEquals(97, rod9c.getAge());

        ConstructorDependenciesBean rod10 = (ConstructorDependenciesBean) xbf.getBean("rod10");
        assertEquals(null, rod10.getName());

        ConstructorDependenciesBean rod11 = (ConstructorDependenciesBean) xbf.getBean("rod11");
        assertEquals(kerry2, rod11.getSpouse1());

        ConstructorDependenciesBean rod12 = (ConstructorDependenciesBean) xbf.getBean("rod12");
        assertEquals(kerry1, rod12.getSpouse1());
        assertNull(rod12.getSpouse2());

        ConstructorDependenciesBean rod13 = (ConstructorDependenciesBean) xbf.getBean("rod13");
        assertEquals(kerry1, rod13.getSpouse1());
        assertEquals(kerry2, rod13.getSpouse2());

        ConstructorDependenciesBean rod14 = (ConstructorDependenciesBean) xbf.getBean("rod14");
        assertEquals(kerry1, rod14.getSpouse1());
        assertEquals(kerry2, rod14.getSpouse2());

        ConstructorDependenciesBean rod15 = (ConstructorDependenciesBean) xbf.getBean("rod15");
        assertEquals(kerry2, rod15.getSpouse1());
        assertEquals(kerry1, rod15.getSpouse2());

        ConstructorDependenciesBean rod16 = (ConstructorDependenciesBean) xbf.getBean("rod16");
        assertEquals(kerry2, rod16.getSpouse1());
        assertEquals(kerry1, rod16.getSpouse2());
        assertEquals(29, rod16.getAge());

        ConstructorDependenciesBean rod17 = (ConstructorDependenciesBean) xbf.getBean("rod17");
        assertEquals(kerry1, rod17.getSpouse1());
        assertEquals(kerry2, rod17.getSpouse2());
        assertEquals(29, rod17.getAge());
    }

    @Test
    public void testPrototypeWithExplicitArguments() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        SimpleConstructorArgBean cd1 = (SimpleConstructorArgBean) xbf.getBean("rod18");
        assertEquals(0, cd1.getAge());
        SimpleConstructorArgBean cd2 = (SimpleConstructorArgBean) xbf.getBean("rod18", 98);
        assertEquals(98, cd2.getAge());
        SimpleConstructorArgBean cd3 = (SimpleConstructorArgBean) xbf.getBean("rod18", "myName");
        assertEquals("myName", cd3.getName());
        SimpleConstructorArgBean cd4 = (SimpleConstructorArgBean) xbf.getBean("rod18");
        assertEquals(0, cd4.getAge());
        SimpleConstructorArgBean cd5 = (SimpleConstructorArgBean) xbf.getBean("rod18", 97);
        assertEquals(97, cd5.getAge());
    }

    @Test
    public void testConstructorArgWithSingleMatch() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        File file = (File) xbf.getBean("file");
        assertEquals(File.separator + "test", file.getPath());
    }

    @Test(expected = BeanCreationException.class)
    public void throwsExceptionOnTooManyArguments() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        xbf.getBean("rod7", ConstructorDependenciesBean.class);
    }

    @Test(expected = UnsatisfiedDependencyException.class)
    public void throwsExceptionOnAmbiguousResolution() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        xbf.getBean("rod8", ConstructorDependenciesBean.class);
    }

    @Test
    public void testDependsOn() {
        doTestDependencies(DEP_DEPENDSON_CONTEXT, 1);
    }

    @Test
    public void testDependsOnInInnerBean() {
        doTestDependencies(DEP_DEPENDSON_INNER_CONTEXT, 4);
    }

    @Test
    public void testDependenciesThroughConstructorArguments() {
        doTestDependencies(DEP_CARG_CONTEXT, 1);
    }

    @Test
    public void testDependenciesThroughConstructorArgumentAutowiring() {
        doTestDependencies(DEP_CARG_AUTOWIRE_CONTEXT, 1);
    }

    @Test
    public void testDependenciesThroughConstructorArgumentsInInnerBean() {
        doTestDependencies(DEP_CARG_INNER_CONTEXT, 1);
    }

    @Test
    public void testDependenciesThroughProperties() {
        doTestDependencies(DEP_PROP, 1);
    }

    @Test
    public void testDependenciesThroughPropertiesWithInTheMiddle() {
        doTestDependencies(DEP_PROP_MIDDLE_CONTEXT, 1);
    }

    @Test
    public void testDependenciesThroughPropertyAutowiringByName() {
        doTestDependencies(DEP_PROP_ABN_CONTEXT, 1);
    }

    @Test
    public void testDependenciesThroughPropertyAutowiringByType() {
        doTestDependencies(DEP_PROP_ABT_CONTEXT, 1);
    }

    @Test
    public void testDependenciesThroughPropertiesInInnerBean() {
        doTestDependencies(DEP_PROP_INNER_CONTEXT, 1);
    }

    private void doTestDependencies(ClassPathResource resource, int nrOfHoldingBeans) {
        PreparingBean1.prepared = false;
        PreparingBean1.destroyed = false;
        PreparingBean2.prepared = false;
        PreparingBean2.destroyed = false;
        DependingBean.destroyCount = 0;
        HoldingBean.destroyCount = 0;
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(resource);
        xbf.preInstantiateSingletons();
        xbf.destroySingletons();
        assertTrue(PreparingBean1.prepared);
        assertTrue(PreparingBean1.destroyed);
        assertTrue(PreparingBean2.prepared);
        assertTrue(PreparingBean2.destroyed);
        assertEquals(nrOfHoldingBeans, DependingBean.destroyCount);
        if (!xbf.getBeansOfType(HoldingBean.class, false, false).isEmpty()) {
            assertEquals(nrOfHoldingBeans, HoldingBean.destroyCount);
        }
    }

    /**
     * When using a BeanFactory. singletons are of course not pre-instantiated.
     * So rubbish class names in bean defs must now not be 'resolved' when the
     * bean def is being parsed, 'cos everything on a bean def is now lazy, but
     * must rather only be picked up when the bean is instantiated.
     */
    @Test
    public void testClassNotFoundWithDefaultBeanClassLoader() {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(factory).loadBeanDefinitions(CLASS_NOT_FOUND_CONTEXT);
        // cool, no errors, so the rubbish class name in the bean def was not resolved
        try {
            // let's resolve the bean definition; must blow up
            factory.getBean("classNotFound");
            fail("Must have thrown a CannotLoadBeanClassException");
        } catch (CannotLoadBeanClassException ex) {
            assertTrue(ex.getResourceDescription().indexOf("classNotFound.xml") != -1);
            assertTrue(ex.getCause() instanceof ClassNotFoundException);
        }
    }

    @Test
    public void testClassNotFoundWithNoBeanClassLoader() {
        DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
        reader.setBeanClassLoader(null);
        reader.loadBeanDefinitions(CLASS_NOT_FOUND_CONTEXT);
        assertEquals("WhatALotOfRubbish", bf.getBeanDefinition("classNotFound").getBeanClassName());
    }

    @Test
    public void testResourceAndInputStream() throws IOException {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(RESOURCE_CONTEXT);
        // comes from "resourceImport.xml"
        ResourceTestBean resource1 = (ResourceTestBean) xbf.getBean("resource1");
        // comes from "resource.xml"
        ResourceTestBean resource2 = (ResourceTestBean) xbf.getBean("resource2");

        assertTrue(resource1.getResource() instanceof ClassPathResource);
        StringWriter writer = new StringWriter();
        FileCopyUtils.copy(new InputStreamReader(resource1.getResource().getInputStream()), writer);
        assertEquals("test", writer.toString());
        writer = new StringWriter();
        FileCopyUtils.copy(new InputStreamReader(resource1.getInputStream()), writer);
        assertEquals("test", writer.toString());
        writer = new StringWriter();
        FileCopyUtils.copy(new InputStreamReader(resource2.getResource().getInputStream()), writer);
        assertEquals("test", writer.toString());
        writer = new StringWriter();
        FileCopyUtils.copy(new InputStreamReader(resource2.getInputStream()), writer);
        assertEquals("test", writer.toString());
    }

    @Test
    public void testClassPathResourceWithImport() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(RESOURCE_CONTEXT);
        // comes from "resourceImport.xml"
        xbf.getBean("resource1", ResourceTestBean.class);
        // comes from "resource.xml"
        xbf.getBean("resource2", ResourceTestBean.class);
    }

    @Test
    public void testUrlResourceWithImport() {
        URL url = getClass().getResource(RESOURCE_CONTEXT.getPath());
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(new UrlResource(url));
        // comes from "resourceImport.xml"
        xbf.getBean("resource1", ResourceTestBean.class);
        // comes from "resource.xml"
        xbf.getBean("resource2", ResourceTestBean.class);
    }

    @Test
    public void testFileSystemResourceWithImport() throws URISyntaxException {
        String file = getClass().getResource(RESOURCE_CONTEXT.getPath()).toURI().getPath();
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(new FileSystemResource(file));
        // comes from "resourceImport.xml"
        xbf.getBean("resource1", ResourceTestBean.class);
        // comes from "resource.xml"
        xbf.getBean("resource2", ResourceTestBean.class);
    }

    @Test(expected = BeanDefinitionStoreException.class)
    public void recursiveImport() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(RECURSIVE_IMPORT_CONTEXT);
    }

    /**
     * @since 3.2.8 and 4.0.2
     * @see <a href="https://jira.spring.io/browse/SPR-10785">SPR-10785</a> and <a
     *      href="https://jira.spring.io/browse/SPR-11420">SPR-11420</a>
     */
    @Test
    public void methodInjectedBeanMustBeOfSameEnhancedCglibSubclassTypeAcrossBeanFactories() {
        Class<?> firstClass = null;

        for (int i = 0; i < 10; i++) {
            DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
            new XmlBeanDefinitionReader(bf).loadBeanDefinitions(OVERRIDES_CONTEXT);

            final Class<?> currentClass = bf.getBean("overrideOneMethod").getClass();
            assertTrue("Method injected bean class [" + currentClass + "] must be a CGLIB enhanced subclass.",
                    ClassUtils.isCglibProxyClass(currentClass));

            if (firstClass == null) {
                firstClass = currentClass;
            } else {
                assertEquals(firstClass, currentClass);
            }
        }
    }

    @Test
    public void lookupOverrideMethodsWithSetterInjection() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(OVERRIDES_CONTEXT);

        lookupOverrideMethodsWithSetterInjection(xbf, "overrideOneMethod", true);
        // Should work identically on subclass definition, in which lookup
        // methods are inherited
        lookupOverrideMethodsWithSetterInjection(xbf, "overrideInheritedMethod", true);

        // Check cost of repeated construction of beans with method overrides
        // Will pick up misuse of CGLIB
        int howMany = 100;
        StopWatch sw = new StopWatch();
        sw.start("Look up " + howMany + " prototype bean instances with method overrides");
        for (int i = 0; i < howMany; i++) {
            lookupOverrideMethodsWithSetterInjection(xbf, "overrideOnPrototype", false);
        }
        sw.stop();
        // System.out.println(sw);
        if (!LogFactory.getLog(DefaultListableBeanFactory.class).isDebugEnabled()) {
            assertTrue(sw.getTotalTimeMillis() < 2000);
        }

        // Now test distinct bean with swapped value in factory, to ensure the two are independent
        OverrideOneMethod swappedOom = (OverrideOneMethod) xbf.getBean("overrideOneMethodSwappedReturnValues");

        TestBean tb = swappedOom.getPrototypeDependency();
        assertEquals("David", tb.getName());
        tb = swappedOom.protectedOverrideSingleton();
        assertEquals("Jenny", tb.getName());
    }

    private void lookupOverrideMethodsWithSetterInjection(BeanFactory xbf, String beanName, boolean singleton) {
        OverrideOneMethod oom = (OverrideOneMethod) xbf.getBean(beanName);

        if (singleton) {
            assertSame(oom, xbf.getBean(beanName));
        } else {
            assertNotSame(oom, xbf.getBean(beanName));
        }

        TestBean jenny1 = oom.getPrototypeDependency();
        assertEquals("Jenny", jenny1.getName());
        TestBean jenny2 = oom.getPrototypeDependency();
        assertEquals("Jenny", jenny2.getName());
        assertNotSame(jenny1, jenny2);

        // Check that the bean can invoke the overridden method on itself
        // This differs from Spring's AOP support, which has a distinct notion
        // of a "target" object, meaning that the target needs explicit knowledge
        // of AOP proxying to invoke an advised method on itself.
        TestBean jenny3 = oom.invokesOverriddenMethodOnSelf();
        assertEquals("Jenny", jenny3.getName());
        assertNotSame(jenny1, jenny3);

        // Now try protected method, and singleton
        TestBean dave1 = oom.protectedOverrideSingleton();
        assertEquals("David", dave1.getName());
        TestBean dave2 = oom.protectedOverrideSingleton();
        assertEquals("David", dave2.getName());
        assertSame(dave1, dave2);
    }

    @Test
    public void testReplaceMethodOverrideWithSetterInjection() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(DELEGATION_OVERRIDES_CONTEXT);

        OverrideOneMethod oom = (OverrideOneMethod) xbf.getBean("overrideOneMethod");

        // Same contract as for overrides.xml
        TestBean jenny1 = oom.getPrototypeDependency();
        assertEquals("Jenny", jenny1.getName());
        TestBean jenny2 = oom.getPrototypeDependency();
        assertEquals("Jenny", jenny2.getName());
        assertNotSame(jenny1, jenny2);

        TestBean notJenny = oom.getPrototypeDependency("someParam");
        assertTrue(!"Jenny".equals(notJenny.getName()));

        // Now try protected method, and singleton
        TestBean dave1 = oom.protectedOverrideSingleton();
        assertEquals("David", dave1.getName());
        TestBean dave2 = oom.protectedOverrideSingleton();
        assertEquals("David", dave2.getName());
        assertSame(dave1, dave2);

        // Check unadvised behaviour
        String str = "woierowijeiowiej";
        assertEquals(str, oom.echo(str));

        // Now test replace
        String s = "this is not a palindrome";
        String reverse = new StringBuffer(s).reverse().toString();
        assertEquals("Should have overridden to reverse, not echo", reverse, oom.replaceMe(s));

        assertEquals("Should have overridden no-arg overloaded replaceMe method to return fixed value",
                FixedMethodReplacer.VALUE, oom.replaceMe());

        OverrideOneMethodSubclass ooms = (OverrideOneMethodSubclass) xbf.getBean("replaceVoidMethod");
        DoSomethingReplacer dos = (DoSomethingReplacer) xbf.getBean("doSomethingReplacer");
        assertEquals(null, dos.lastArg);
        String s1 = "";
        String s2 = "foo bar black sheep";
        ooms.doSomething(s1);
        assertEquals(s1, dos.lastArg);
        ooms.doSomething(s2);
        assertEquals(s2, dos.lastArg);
    }

    @Test
    public void lookupOverrideOneMethodWithConstructorInjection() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(CONSTRUCTOR_OVERRIDES_CONTEXT);

        ConstructorInjectedOverrides cio = (ConstructorInjectedOverrides) xbf.getBean("constructorOverrides");

        // Check that the setter was invoked...
        // We should be able to combine Constructor and
        // Setter Injection
        assertEquals("Setter string was set", "from property element", cio.getSetterString());

        // Jenny is a singleton
        TestBean jenny = (TestBean) xbf.getBean("jenny");
        assertSame(jenny, cio.getTestBean());
        assertSame(jenny, cio.getTestBean());
        FactoryMethods fm1 = cio.createFactoryMethods();
        FactoryMethods fm2 = cio.createFactoryMethods();
        assertNotSame("FactoryMethods reference is to a prototype", fm1, fm2);
        assertSame("The two prototypes hold the same singleton reference", fm1.getTestBean(), fm2.getTestBean());
    }

    @Test
    public void testRejectsOverrideOfBogusMethodName() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        try {
            reader.loadBeanDefinitions(INVALID_NO_SUCH_METHOD_CONTEXT);
            xbf.getBean("constructorOverrides");
            fail("Shouldn't allow override of bogus method");
        } catch (BeanDefinitionStoreException ex) {
            // Check that the bogus method name was included in the error message
            assertTrue("Bogus method name correctly reported", ex.getMessage().indexOf("bogusMethod") != -1);
        }
    }

    @Test
    public void serializableMethodReplacerAndSuperclass() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(DELEGATION_OVERRIDES_CONTEXT);
        SerializableMethodReplacerCandidate s = (SerializableMethodReplacerCandidate) xbf
                .getBean("serializableReplacer");
        String forwards = "this is forwards";
        String backwards = new StringBuffer(forwards).reverse().toString();
        assertEquals(backwards, s.replaceMe(forwards));
        // SPR-356: lookup methods & method replacers are not serializable.
        assertFalse("Lookup methods and method replacers are not meant to be serializable.",
                SerializationTestUtils.isSerializable(s));
    }

    @Test
    public void testInnerBeanInheritsScopeFromConcreteChildDefinition() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(OVERRIDES_CONTEXT);
        TestBean jenny = (TestBean) xbf.getBean("jennyChild");
        assertEquals(1, jenny.getFriends().size());
        assertTrue(jenny.getFriends().iterator().next() instanceof TestBean);
    }

    @Test
    public void testConstructorArgWithSingleSimpleTypeMatch() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);

        SingleSimpleTypeConstructorBean bean = (SingleSimpleTypeConstructorBean) xbf.getBean("beanWithBoolean");
        assertTrue(bean.isSingleBoolean());

        SingleSimpleTypeConstructorBean bean2 = (SingleSimpleTypeConstructorBean) xbf.getBean("beanWithBoolean2");
        assertTrue(bean2.isSingleBoolean());
    }

    @Test
    public void testConstructorArgWithDoubleSimpleTypeMatch() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);

        SingleSimpleTypeConstructorBean bean = (SingleSimpleTypeConstructorBean) xbf
                .getBean("beanWithBooleanAndString");
        assertTrue(bean.isSecondBoolean());
        assertEquals("A String", bean.getTestString());

        SingleSimpleTypeConstructorBean bean2 = (SingleSimpleTypeConstructorBean) xbf
                .getBean("beanWithBooleanAndString2");
        assertTrue(bean2.isSecondBoolean());
        assertEquals("A String", bean2.getTestString());
    }

    @Test
    public void testDoubleBooleanAutowire() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        DoubleBooleanConstructorBean bean = (DoubleBooleanConstructorBean) xbf.getBean("beanWithDoubleBoolean");
        assertEquals(Boolean.TRUE, bean.boolean1);
        assertEquals(Boolean.FALSE, bean.boolean2);
    }

    @Test
    public void testDoubleBooleanAutowireWithIndex() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        DoubleBooleanConstructorBean bean = (DoubleBooleanConstructorBean) xbf
                .getBean("beanWithDoubleBooleanAndIndex");
        assertEquals(Boolean.FALSE, bean.boolean1);
        assertEquals(Boolean.TRUE, bean.boolean2);
    }

    @Test
    public void testLenientDependencyMatching() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        LenientDependencyTestBean bean = (LenientDependencyTestBean) xbf.getBean("lenientDependencyTestBean");
        assertTrue(bean.tb instanceof DerivedTestBean);
    }

    @Test
    public void testLenientDependencyMatchingFactoryMethod() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        LenientDependencyTestBean bean = (LenientDependencyTestBean) xbf
                .getBean("lenientDependencyTestBeanFactoryMethod");
        assertTrue(bean.tb instanceof DerivedTestBean);
    }

    @Test
    public void testNonLenientDependencyMatching() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("lenientDependencyTestBean");
        bd.setLenientConstructorResolution(false);
        try {
            xbf.getBean("lenientDependencyTestBean");
            fail("Should have thrown BeanCreationException");
        } catch (BeanCreationException ex) {
            // expected
            ex.printStackTrace();
            assertTrue(ex.getMostSpecificCause().getMessage().contains("Ambiguous"));
        }
    }

    @Test
    public void testNonLenientDependencyMatchingFactoryMethod() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf
                .getBeanDefinition("lenientDependencyTestBeanFactoryMethod");
        bd.setLenientConstructorResolution(false);
        try {
            xbf.getBean("lenientDependencyTestBeanFactoryMethod");
            fail("Should have thrown BeanCreationException");
        } catch (BeanCreationException ex) {
            // expected
            ex.printStackTrace();
            assertTrue(ex.getMostSpecificCause().getMessage().contains("Ambiguous"));
        }
    }

    @Test
    public void testJavaLangStringConstructor() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("string");
        bd.setLenientConstructorResolution(false);
        String str = (String) xbf.getBean("string");
        assertEquals("test", str);
    }

    @Test
    public void testCustomStringConstructor() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("stringConstructor");
        bd.setLenientConstructorResolution(false);
        StringConstructorTestBean tb = (StringConstructorTestBean) xbf.getBean("stringConstructor");
        assertEquals("test", tb.name);
    }

    @Test
    public void testPrimitiveConstructorArray() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        ConstructorArrayTestBean bean = (ConstructorArrayTestBean) xbf.getBean("constructorArray");
        assertTrue(bean.array instanceof int[]);
        assertEquals(1, ((int[]) bean.array).length);
        assertEquals(1, ((int[]) bean.array)[0]);
    }

    @Test
    public void testIndexedPrimitiveConstructorArray() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        ConstructorArrayTestBean bean = (ConstructorArrayTestBean) xbf.getBean("indexedConstructorArray");
        assertTrue(bean.array instanceof int[]);
        assertEquals(1, ((int[]) bean.array).length);
        assertEquals(1, ((int[]) bean.array)[0]);
    }

    @Test
    public void testStringConstructorArrayNoType() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        ConstructorArrayTestBean bean = (ConstructorArrayTestBean) xbf.getBean("constructorArrayNoType");
        assertTrue(bean.array instanceof String[]);
        assertEquals(0, ((String[]) bean.array).length);
    }

    @Test
    public void testStringConstructorArrayNoTypeNonLenient() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("constructorArrayNoType");
        bd.setLenientConstructorResolution(false);
        ConstructorArrayTestBean bean = (ConstructorArrayTestBean) xbf.getBean("constructorArrayNoType");
        assertTrue(bean.array instanceof String[]);
        assertEquals(0, ((String[]) bean.array).length);
    }

    @Test
    public void testConstructorWithUnresolvableParameterName() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT);
        AtomicInteger bean = (AtomicInteger) xbf.getBean("constructorUnresolvableName");
        assertEquals(1, bean.get());
        bean = (AtomicInteger) xbf.getBean("constructorUnresolvableNameWithIndex");
        assertEquals(1, bean.get());
    }

    @Test
    public void testWithDuplicateName() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        try {
            new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(TEST_WITH_DUP_NAMES_CONTEXT);
            fail("Duplicate name not detected");
        } catch (BeansException ex) {
            assertTrue(ex.getMessage().contains("Bean name 'foo'"));
        }
    }

    @Test
    public void testWithDuplicateNameInAlias() throws Exception {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        try {
            new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(TEST_WITH_DUP_NAME_IN_ALIAS_CONTEXT);
            fail("Duplicate name not detected");
        } catch (BeansException e) {
            assertTrue(e.getMessage().contains("Bean name 'foo'"));
        }
    }

    @Test
    public void testOverrideMethodByArgTypeAttribute() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(DELEGATION_OVERRIDES_CONTEXT);
        OverrideOneMethod oom = (OverrideOneMethod) xbf.getBean("overrideOneMethodByAttribute");
        assertEquals("should not replace", "replaceMe:1", oom.replaceMe(1));
        assertEquals("should replace", "cba", oom.replaceMe("abc"));
    }

    @Test
    public void testOverrideMethodByArgTypeElement() {
        DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
        reader.loadBeanDefinitions(DELEGATION_OVERRIDES_CONTEXT);
        OverrideOneMethod oom = (OverrideOneMethod) xbf.getBean("overrideOneMethodByElement");
        assertEquals("should not replace", "replaceMe:1", oom.replaceMe(1));
        assertEquals("should replace", "cba", oom.replaceMe("abc"));
    }

    public static class DoSomethingReplacer implements MethodReplacer {

        public Object lastArg;

        @Override
        public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
            assertEquals(1, args.length);
            assertEquals("doSomething", method.getName());
            lastArg = args[0];
            return null;
        }
    }

    public static class BadInitializer {

        /** Init method */
        public void init2() throws IOException {
            throw new IOException();
        }
    }

    public static class DoubleInitializer {

        private int num;

        public int getNum() {
            return num;
        }

        public void setNum(int i) {
            num = i;
        }

        /** Init method */
        public void init() {
            this.num *= 2;
        }
    }

    public static class InitAndIB implements InitializingBean, DisposableBean {

        public static boolean constructed;

        public boolean afterPropertiesSetInvoked, initMethodInvoked, destroyed, customDestroyed;

        public InitAndIB() {
            constructed = true;
        }

        @Override
        public void afterPropertiesSet() {
            if (this.initMethodInvoked) {
                fail();
            }
            if (this.afterPropertiesSetInvoked) {
                throw new IllegalStateException("Already initialized");
            }
            this.afterPropertiesSetInvoked = true;
        }

        /** Init method */
        public void customInit() throws IOException {
            if (!this.afterPropertiesSetInvoked) {
                fail();
            }
            if (this.initMethodInvoked) {
                throw new IllegalStateException("Already customInitialized");
            }
            this.initMethodInvoked = true;
        }

        @Override
        public void destroy() {
            if (this.customDestroyed) {
                fail();
            }
            if (this.destroyed) {
                throw new IllegalStateException("Already destroyed");
            }
            this.destroyed = true;
        }

        public void customDestroy() {
            if (!this.destroyed) {
                fail();
            }
            if (this.customDestroyed) {
                throw new IllegalStateException("Already customDestroyed");
            }
            this.customDestroyed = true;
        }
    }

    public static class PreparingBean1 implements DisposableBean {

        public static boolean prepared = false;

        public static boolean destroyed = false;

        public PreparingBean1() {
            prepared = true;
        }

        @Override
        public void destroy() {
            destroyed = true;
        }
    }

    public static class PreparingBean2 implements DisposableBean {

        public static boolean prepared = false;

        public static boolean destroyed = false;

        public PreparingBean2() {
            prepared = true;
        }

        @Override
        public void destroy() {
            destroyed = true;
        }
    }

    public static class DependingBean implements InitializingBean, DisposableBean {

        public static int destroyCount = 0;

        public boolean destroyed = false;

        public DependingBean() {
        }

        public DependingBean(PreparingBean1 bean1, PreparingBean2 bean2) {
        }

        public void setBean1(PreparingBean1 bean1) {
        }

        public void setBean2(PreparingBean2 bean2) {
        }

        public void setInTheMiddleBean(InTheMiddleBean bean) {
        }

        @Override
        public void afterPropertiesSet() {
            if (!(PreparingBean1.prepared && PreparingBean2.prepared)) {
                throw new IllegalStateException("Need prepared PreparingBeans!");
            }
        }

        @Override
        public void destroy() {
            if (PreparingBean1.destroyed || PreparingBean2.destroyed) {
                throw new IllegalStateException("Should not be destroyed after PreparingBeans");
            }
            destroyed = true;
            destroyCount++;
        }
    }

    public static class InTheMiddleBean {

        public void setBean1(PreparingBean1 bean1) {
        }

        public void setBean2(PreparingBean2 bean2) {
        }
    }

    public static class HoldingBean implements DisposableBean {

        public static int destroyCount = 0;

        private DependingBean dependingBean;

        public boolean destroyed = false;

        public void setDependingBean(DependingBean dependingBean) {
            this.dependingBean = dependingBean;
        }

        @Override
        public void destroy() {
            if (this.dependingBean.destroyed) {
                throw new IllegalStateException("Should not be destroyed after DependingBean");
            }
            this.destroyed = true;
            destroyCount++;
        }
    }

    public static class DoubleBooleanConstructorBean {

        private Boolean boolean1;
        private Boolean boolean2;

        public DoubleBooleanConstructorBean(Boolean b1, Boolean b2) {
            this.boolean1 = b1;
            this.boolean2 = b2;
        }

        public DoubleBooleanConstructorBean(String s1, String s2) {
            throw new IllegalStateException("Don't pick this constructor");
        }

        public static DoubleBooleanConstructorBean create(Boolean b1, Boolean b2) {
            return new DoubleBooleanConstructorBean(b1, b2);
        }

        public static DoubleBooleanConstructorBean create(String s1, String s2) {
            return new DoubleBooleanConstructorBean(s1, s2);
        }
    }

    public static class LenientDependencyTestBean {

        public final ITestBean tb;

        public LenientDependencyTestBean(ITestBean tb) {
            this.tb = tb;
        }

        public LenientDependencyTestBean(TestBean tb) {
            this.tb = tb;
        }

        public LenientDependencyTestBean(DerivedTestBean tb) {
            this.tb = tb;
        }

        @SuppressWarnings("rawtypes")
        public LenientDependencyTestBean(Map[] m) {
            throw new IllegalStateException("Don't pick this constructor");
        }

        public static LenientDependencyTestBean create(ITestBean tb) {
            return new LenientDependencyTestBean(tb);
        }

        public static LenientDependencyTestBean create(TestBean tb) {
            return new LenientDependencyTestBean(tb);
        }

        public static LenientDependencyTestBean create(DerivedTestBean tb) {
            return new LenientDependencyTestBean(tb);
        }
    }

    public static class ConstructorArrayTestBean {

        public final Object array;

        public ConstructorArrayTestBean(int[] array) {
            this.array = array;
        }

        public ConstructorArrayTestBean(float[] array) {
            this.array = array;
        }

        public ConstructorArrayTestBean(short[] array) {
            this.array = array;
        }

        public ConstructorArrayTestBean(String[] array) {
            this.array = array;
        }
    }

    public static class StringConstructorTestBean {

        public final String name;

        public StringConstructorTestBean(String name) {
            this.name = name;
        }
    }

    public static class WrappingPostProcessor implements BeanPostProcessor {

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            ProxyFactory pf = new ProxyFactory(bean);
            return pf.getProxy();
        }
    }

}