SPRNET-620 - Support for Collection Merging in Parent/Child Object Definitions
This commit is contained in:
@@ -199,7 +199,7 @@
|
||||
<!-- additional collaborators and configuration for this object go here -->
|
||||
</object>
|
||||
|
||||
<!-- more bean definitions for services go here -->
|
||||
<!-- more object definitions for services go here -->
|
||||
|
||||
</objects></programlisting>The following example shows the data access
|
||||
objects <literal>(daos.xml)</literal> configuration file:</para>
|
||||
@@ -207,14 +207,14 @@
|
||||
<programlisting><objects xmlns="http://www.springframework.net">
|
||||
|
||||
<object id="AccountDao" type="Petstore.Dao.HibernateAccountDao, PetStore">
|
||||
<!-- additional collaborators and configuration for this bean go here -->
|
||||
<!-- additional collaborators and configuration for this object go here -->
|
||||
</object>
|
||||
|
||||
<object id="ItemDao" type="Petstore.Dao.HibernateItemDao, PetStore">
|
||||
<!-- additional collaborators and configuration for this bean go here -->
|
||||
<!-- additional collaborators and configuration for this object go here -->
|
||||
</object>
|
||||
|
||||
<!-- more bean definitions for data access objects go here -->
|
||||
<!-- more object definitions for data access objects go here -->
|
||||
</objects></programlisting>
|
||||
|
||||
<para>In the preceeding example, the service layer consists of the class
|
||||
@@ -436,7 +436,7 @@
|
||||
that these paths are relative, it is better form not to use the slash
|
||||
at all. The contents of the files being imported, including the top
|
||||
level <literal><objects/></literal> element, must be valid XML
|
||||
bean definitions according to the Spring Schema.</para>
|
||||
object definitions according to the Spring Schema.</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
@@ -453,7 +453,7 @@
|
||||
<para>The <literal>IApplicationContext</literal> enables you to read
|
||||
object definitions and access them as follows:</para>
|
||||
|
||||
<programlisting language="csharp">// create and configure beans
|
||||
<programlisting language="csharp">// create and configure objects
|
||||
IApplicationContext context = new XmlApplicationContext("services.xml", "daos.xml");
|
||||
|
||||
// retrieve configured instance
|
||||
@@ -1037,8 +1037,8 @@ public class TestGenericObjectFactory
|
||||
instance after it is constructed. (Factory methods may be considered a
|
||||
special case of providing constructor arguments for the purposes of this
|
||||
description). The container injects these dependencies when it creates
|
||||
the bean. This process is fundamentally the inverse to the case when the
|
||||
bean itself is controlling the instantiation or location of its
|
||||
the object. This process is fundamentally the inverse to the case when
|
||||
the object itself is controlling the instantiation or location of its
|
||||
dependencies by using direct construction of classes, or the Service
|
||||
Locator pattern. The inverting of this responsibility is why the name
|
||||
Inversion of Control (IoC) is used to describe the container's
|
||||
@@ -1725,9 +1725,9 @@ public class MixedIocObject
|
||||
no validation is performed on the value that is passed to the
|
||||
<literal>targetName</literal> property of the client object. Typos
|
||||
are only discovered (with ost mikely fatal results) when the
|
||||
'client' object is actually instantiated. If the 'client' bean is a
|
||||
prototype bean, this typo and the resulting exception may only be
|
||||
discovered long after the container is deployed.</para>
|
||||
'client' object is actually instantiated. If the 'client' object is
|
||||
a prototype object, this typo and the resulting exception may only
|
||||
be discovered long after the container is deployed.</para>
|
||||
|
||||
<para>Additionally, if the reference object is in the same XML unit,
|
||||
and the object name is the object <emphasis>id</emphasis>, you can
|
||||
@@ -1770,7 +1770,7 @@ public class MixedIocObject
|
||||
collaborator is a singleton object it may be initialized already by
|
||||
the container.) All references are ultimately just a reference to
|
||||
another object. Scoping and validation depend on whether you specify
|
||||
the id/name of the object through the <literal>bean</literal>,
|
||||
the id/name of the object through the <literal>object</literal>,
|
||||
<literal>local</literal>, or <literal>parent</literal>
|
||||
attributes.</para>
|
||||
|
||||
@@ -1802,16 +1802,16 @@ public class MixedIocObject
|
||||
the values in the '<literal>name'</literal> attribute of the target
|
||||
object, and the target object must be in a parent container to the
|
||||
current one. You us ethis object reference variant mainly when you
|
||||
have a hierarchy of containers and you want to wrap an existing bean
|
||||
have a hierarchy of containers and you want to wrap an existing object
|
||||
in a parent container with some sort of proxy which will have the same
|
||||
name as the parent bean.<programlisting language="myxml"><!-- in the parent context -->
|
||||
name as the parent object.<programlisting language="myxml"><!-- in the parent context -->
|
||||
<object id="AccountService" type="MyApp.SimpleAccountService, MyApp">
|
||||
<!-- insert dependencies as required as here -->
|
||||
<!-- insert dependencies as required as here -->
|
||||
</object></programlisting><programlisting><!-- in the child (descendant) context -->
|
||||
<object id="AccountService" <-- notice that the name of this bean is the same as the name of the 'parent' bean
|
||||
type="Spring.Aop.Framework.ProxyFactoryBean, Spring.Aop">
|
||||
<object id="AccountService" <-- notice that the name of this object is the same as the name of the 'parent' object
|
||||
type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
|
||||
<property name="target">
|
||||
<ref parent="AccountService"/> <-- notice how we refer to the parent bean -->
|
||||
<ref parent="AccountService"/> <-- notice how we refer to the parent object -->
|
||||
</property>
|
||||
<!-- insert other configuration and dependencies as required as here -->
|
||||
</object></programlisting></para>
|
||||
@@ -1841,7 +1841,7 @@ public class MixedIocObject
|
||||
<literal>scope</literal> flag. Inner object are
|
||||
<emphasis>always</emphasis> anonymous and they are
|
||||
<emphasis>always</emphasis> scoped as prototypes. It is not possible
|
||||
to inject inner objects into collaborating beans other than into the
|
||||
to inject inner objects into collaborating objects other than into the
|
||||
enclosing object.</para>
|
||||
</sect3>
|
||||
|
||||
@@ -2032,6 +2032,85 @@ public class MixedIocObject
|
||||
</object></programlisting></para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Collection Merging</title>
|
||||
|
||||
<para>As of Spring 1.3, the container supports the merging of
|
||||
collections. An application developer can define a parent-style
|
||||
<literal><list/></literal>,
|
||||
<literal><dictionary/></literal>,
|
||||
<literal><set/></literal> or
|
||||
<literal><name-value/></literal> element, and have child-style
|
||||
<literal><list/></literal>,
|
||||
<literal><dictionary/></literal>,
|
||||
<literal><set/></literal> or
|
||||
<literal><name-value/></literal> elements inherit and override
|
||||
values from the parent collection. That is, the child collection's
|
||||
values are the result of merging the elements of the parent and child
|
||||
collections, with the child's collection elements overriding values
|
||||
specified in the parent collection.</para>
|
||||
|
||||
<para><emphasis>This section on merging discusses the parent-child
|
||||
object mechanism. Readers unfamiliar with parent and child object
|
||||
definitions may wish to read the <link
|
||||
linkend="objects-childobjects">relevant section</link> before
|
||||
continuing.</emphasis></para>
|
||||
|
||||
<para>The following example demonstrates collection merging:</para>
|
||||
|
||||
<programlisting> <object id="parent" abstract="true" type="Example.ComplexObject, Examples">
|
||||
<property name="AdminEmails">
|
||||
<name-values>
|
||||
<add key="administrator" value="administrator@example.com"/>
|
||||
<add key="support" value="support@example.com"/>
|
||||
</name-values>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object id="child" parent="parent" >
|
||||
<property name="AdminEmails">
|
||||
<!-- the merge is specified on the *child* collection definition -->
|
||||
<name-values merge="true">
|
||||
<add key="sales" value="sales@example.com"/>
|
||||
<add key="support" value="support@example.co.uk"/>
|
||||
</name-values>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
|
||||
<para>Notice the use of the <literal>merge=true</literal> attribute on
|
||||
the <literal><name-values/></literal> element of the
|
||||
<literal>AdminEmails</literal> property of the child object
|
||||
definition. When the child object is resolved and instantiated by the
|
||||
container, the resulting instance has an
|
||||
<literal>AdminEmails</literal> Properties collection that contains the
|
||||
result of the merging of the child's <literal>AdminEmails</literal>
|
||||
collection with the parent's <literal>AdminEmails</literal>
|
||||
collection.</para>
|
||||
|
||||
<programlisting>administrator=administrator@example.com
|
||||
sales=sales@example.com
|
||||
support=support@example.co.uk</programlisting>
|
||||
|
||||
<para>The child Properties collection's value set inherits all
|
||||
property elements from the parent
|
||||
<literal><name-values/></literal>, and the child's value for the
|
||||
support value overrides the value in the parent collection. This
|
||||
merging behavior applies similarly to the
|
||||
<literal><list/></literal>,
|
||||
<literal><dictionary/></literal>, and
|
||||
<literal><set/></literal> collection types. In the specific case
|
||||
of the <literal><list/></literal> element, the semantics
|
||||
associated with the <literal>IList</literal> collection type, that is,
|
||||
the notion of an ordered collection of values, is maintained; the
|
||||
parent's values precede all of the child list's values. In the case of
|
||||
the <literal>IDictionary</literal>, <literal>ISet</literal>, and
|
||||
<literal>NameValue</literal> collection types, no ordering exists.
|
||||
Hence no ordering semantics are in effect for the collection types
|
||||
that underlie the associated <literal>IDictionary</literal>,
|
||||
<literal>ISet</literal>, and <literal>NameValueCollection</literal>
|
||||
implementation types that the container uses internally.</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 xml:id="objects-null-values">
|
||||
<title>Null and empty values</title>
|
||||
|
||||
@@ -2388,11 +2467,11 @@ source.OnClick(); // First eventListener1.HandleEvent is invoked, then eventList
|
||||
<para>If an object is a dependency of another that usually means that
|
||||
one object is set as a property of another. Typically you accomplish
|
||||
this with the <literal><ref/></literal> element in XML-based
|
||||
configuration metadata. However, sometimes dependencies between beans
|
||||
configuration metadata. However, sometimes dependencies between objects
|
||||
are less direct; for example, a static initializer in a class needs to
|
||||
be triggered, such as device driver registration. The
|
||||
<literal>depends-on</literal> attribute can explicitly force one or more
|
||||
beans to be initialized before the bean using this element is
|
||||
objects to be initialized before the object using this element is
|
||||
initialized. The following example uses the
|
||||
<literal>depends-on</literal> attribute to express a dependency on a
|
||||
single object: <programlisting language="myxml"><object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager">
|
||||
@@ -2452,13 +2531,13 @@ source.OnClick(); // First eventListener1.HandleEvent is invoked, then eventList
|
||||
<literal>IApplicationContext</literal> is starting up, whereas the
|
||||
<literal>not.lazy</literal> object is eagerly pre-instantiated.</para>
|
||||
|
||||
<para>However, when a lazy-initialized bean is a dependency of a
|
||||
<para>However, when a lazy-initialized object is a dependency of a
|
||||
singleton object that is <emphasis>not</emphasis>
|
||||
<literal>lazy-initialized</literal>, the
|
||||
<classname>IApplicationContext</classname> creates the lazy-initialized
|
||||
bean at startup, because it must satisfy the singleton's dependencies.
|
||||
The lazy-initialized bean is injected into a singleton object elsewhere
|
||||
that is not lazy-initialized.</para>
|
||||
object at startup, because it must satisfy the singleton's dependencies.
|
||||
The lazy-initialized object is injected into a singleton object
|
||||
elsewhere that is not lazy-initialized.</para>
|
||||
|
||||
<para>You can also control lazy-initialization at the container level by
|
||||
using the <literal>default-lazy-init </literal>attribute on the
|
||||
@@ -3460,7 +3539,7 @@ public class MyClassFactory
|
||||
prototype objects, be aware that <emphasis>dependencies are resolved at
|
||||
instantiation time</emphasis>. Thus if you dependency-inject a
|
||||
prototype-scoped objects into a singleton-scoped object, a new prototype
|
||||
bean is instantiated and then dependency-injected into the singleton
|
||||
object is instantiated and then dependency-injected into the singleton
|
||||
object. The prototype instance is the sole instance that is ever
|
||||
supplied to the singleton-scoped object.</para>
|
||||
|
||||
|
||||
@@ -180,17 +180,35 @@ namespace Spring.Objects.Factory.Config
|
||||
GenericArgumentValues.Add(o);
|
||||
}
|
||||
foreach (DictionaryEntry entry in other.IndexedArgumentValues)
|
||||
{
|
||||
IndexedArgumentValues.Add(entry.Key, entry.Value);
|
||||
{
|
||||
ValueHolder vh = entry.Value as ValueHolder;
|
||||
if (vh != null)
|
||||
{
|
||||
AddOrMergeIndexedArgumentValues( (int) entry.Key, vh.Copy());
|
||||
}
|
||||
}
|
||||
foreach (DictionaryEntry entry in other.NamedArgumentValues)
|
||||
{
|
||||
NamedArgumentValues.Add(entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddOrMergeIndexedArgumentValues(int key, ValueHolder newValue)
|
||||
{
|
||||
ValueHolder currentValue = _indexedArgumentValues[key] as ValueHolder;
|
||||
IMergable mergable = newValue.Value as IMergable;
|
||||
if (currentValue != null && mergable != null )
|
||||
{
|
||||
if (mergable.MergeEnabled)
|
||||
{
|
||||
newValue.Value = mergable.Merge(currentValue.Value);
|
||||
}
|
||||
}
|
||||
_indexedArgumentValues[key] = newValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Add argument value for the given index in the constructor argument list.
|
||||
/// </summary>
|
||||
/// <param name="index">
|
||||
@@ -599,7 +617,13 @@ namespace Spring.Objects.Factory.Config
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
#region Methods
|
||||
|
||||
public ValueHolder Copy()
|
||||
{
|
||||
ValueHolder copy = new ValueHolder(this._ctorValue, this.typeName);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="System.String"/> that represents the current
|
||||
@@ -650,7 +674,7 @@ namespace Spring.Objects.Factory.Config
|
||||
private object _ctorValue;
|
||||
private string typeName;
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
|
||||
<object id="parentWithList" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="SomeList">
|
||||
<property name="SomeGenericStringList">
|
||||
<list>
|
||||
<value>Rob Harrop</value>
|
||||
<value>Rod Johnson</value>
|
||||
@@ -12,13 +12,22 @@
|
||||
</object>
|
||||
|
||||
<object id="childWithList" parent="parentWithList">
|
||||
<property name="SomeList">
|
||||
<property name="SomeGenericStringList">
|
||||
<list merge="true">
|
||||
<value>Juergen Hoeller</value>
|
||||
</list>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object id="childWithListOfRefs" parent="parentWithList">
|
||||
<property name="SomeList">
|
||||
<list merge="true">
|
||||
<object type="Spring.Objects.TestObject, Spring.Core.Tests"/>
|
||||
</list>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
|
||||
|
||||
<object id="parentWithSet" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="SomeSet">
|
||||
@@ -36,6 +45,17 @@
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object id="childWithSetOfRefs" parent="parentWithSet">
|
||||
<property name="SomeSet">
|
||||
<set merge="true">
|
||||
<object type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="Name" value="Sally"/>
|
||||
</object>
|
||||
</set>
|
||||
</property>
|
||||
|
||||
</object>
|
||||
|
||||
<object id="parentWithMap" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="SomeMap">
|
||||
<dictionary>
|
||||
@@ -55,6 +75,19 @@
|
||||
</property>
|
||||
</object>
|
||||
|
||||
|
||||
<object id="childWithMapOfRefs" parent="parentWithMap">
|
||||
<property name="SomeMap">
|
||||
<dictionary merge="true">
|
||||
<entry key="Rob">
|
||||
<object type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="Name" value="Sally"/>
|
||||
</object>
|
||||
</entry>
|
||||
</dictionary>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object id="parentWithNameValues" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="SomeNameValueCollection">
|
||||
<name-values>
|
||||
@@ -72,4 +105,106 @@
|
||||
</name-values>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
|
||||
<object name="parentWithListInConstructor" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<constructor-arg index="0">
|
||||
<list>
|
||||
<value>Rob Harrop</value>
|
||||
<value>Rod Johnson</value>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
|
||||
<object name="childWithListInConstructor" parent="parentWithListInConstructor">
|
||||
<constructor-arg index="0">
|
||||
<list merge="true">
|
||||
<value>Juergen Hoeller</value>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="childWithListOfRefsInConstructor" parent="parentWithListInConstructor">
|
||||
<constructor-arg index="0">
|
||||
<list merge="true">
|
||||
<object type="Spring.Objects.TestObject, Spring.Core.Tests"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="parentWithSetInConstructor" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<constructor-arg index="0">
|
||||
<set>
|
||||
<value>Rob Harrop</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="childWithSetInConstructor" parent="parentWithSetInConstructor">
|
||||
<constructor-arg index="0">
|
||||
<set merge="true">
|
||||
<value>Sally Greenwood</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="childWithSetOfRefsInConstructor" parent="parentWithSetInConstructor">
|
||||
<constructor-arg index="0">
|
||||
<set merge="true">
|
||||
<object type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="Name" value="Sally"/>
|
||||
</object>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="parentWithMapInConstructor" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<constructor-arg index="0">
|
||||
<dictionary>
|
||||
<entry key="Rob" value="Sall"/>
|
||||
<entry key="Juergen" value="Eva"/>
|
||||
</dictionary>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="childWithMapInConstructor" parent="parentWithMapInConstructor">
|
||||
<constructor-arg index="0">
|
||||
<dictionary merge="true">
|
||||
<entry key="Rod" value="Kerry"/>
|
||||
<entry key="Rob" value="Sally"/>
|
||||
</dictionary>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="childWithMapOfRefsInConstructor" parent="parentWithMapInConstructor">
|
||||
<constructor-arg index="0">
|
||||
<dictionary merge="true">
|
||||
<entry key="Rob">
|
||||
<object type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="Name" value="Sally"/>
|
||||
</object>
|
||||
</entry>
|
||||
</dictionary>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="parentWithPropsInConstructor" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<constructor-arg index="0">
|
||||
<name-values>
|
||||
<add key="Rob" value="Sall"/>
|
||||
<add key="Rod" value="Kerry"/>
|
||||
</name-values>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
<object name="childWithPropsInConstructor" parent="parentWithPropsInConstructor">
|
||||
<constructor-arg index="0">
|
||||
<name-values merge="true">
|
||||
<add key="Juergen" value="Eva"/>
|
||||
<add key="Rob" value="Sally"/>
|
||||
</name-values>
|
||||
</constructor-arg>
|
||||
</object>
|
||||
|
||||
</objects>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
|
||||
<object id="parentWithList" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="SomeList">
|
||||
<list element-type="string">
|
||||
<value>Rob Harrop</value>
|
||||
<value>Rod Johnson</value>
|
||||
</list>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object id="childWithList" parent="parentWithList">
|
||||
<property name="SomeList">
|
||||
<list merge="true" element-type="string">
|
||||
<value>Juergen Hoeller</value>
|
||||
</list>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
|
||||
</objects>
|
||||
@@ -0,0 +1,68 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2009 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.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#if !NET_1_1
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using NUnit.Framework;
|
||||
using Spring.Collections;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Objects.Factory.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// Unit and integration tests for the collection merging support
|
||||
/// </summary>
|
||||
/// <author>Rod Johnson</author>
|
||||
/// <author>Rick Evans</author>
|
||||
/// <author>Mark Pollack (.NET)</author>
|
||||
[TestFixture]
|
||||
[Ignore("SPRNET-1242 Support for collection merging with generic collections")]
|
||||
public class CollectionMergingGenericTests
|
||||
{
|
||||
private DefaultListableObjectFactory objectFactory;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
this.objectFactory = new DefaultListableObjectFactory();
|
||||
IObjectDefinitionReader reader = new XmlObjectDefinitionReader(this.objectFactory);
|
||||
reader.LoadObjectDefinitions(new ReadOnlyXmlTestResource("collectionMergingGeneric.xml", GetType()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeList()
|
||||
{
|
||||
TestObject to = (TestObject) this.objectFactory.GetObject("childWithList");
|
||||
System.Collections.Generic.List<string> list = to.SomeGenericStringList;
|
||||
Assert.That(3, Is.EqualTo(list.Count));
|
||||
Assert.That("Rob Harrop", Is.EqualTo(list[0]));
|
||||
Assert.That("Rod Johnson", Is.EqualTo(list[1]));
|
||||
Assert.That("Juergen Hoeller", Is.EqualTo(list[2]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -61,6 +61,17 @@ namespace Spring.Objects.Factory.Xml
|
||||
Assert.That("Juergen Hoeller", Is.EqualTo(list[2]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergListWithInnerObjectAsListElement()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithListOfRefs");
|
||||
IList list = to.SomeList;
|
||||
Assert.IsNotNull(list);
|
||||
Assert.AreEqual(3, list.Count);
|
||||
Assert.IsNotNull(list[2]);
|
||||
Assert.That(list[2], Is.InstanceOf(typeof (TestObject)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeSet()
|
||||
{
|
||||
@@ -71,6 +82,22 @@ namespace Spring.Objects.Factory.Xml
|
||||
Assert.IsTrue(set.Contains("Sally Greenwood"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeSetWithInnerObjectAsSetElement()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithSetOfRefs");
|
||||
ISet set = to.SomeSet;
|
||||
Assert.IsNotNull(set);
|
||||
Assert.AreEqual(2, set.Count);
|
||||
IEnumerator enumerator = set.GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
enumerator.MoveNext();
|
||||
object o = enumerator.Current;
|
||||
Assert.IsNotNull(o);
|
||||
Assert.That(o, Is.InstanceOf(typeof(TestObject)));
|
||||
Assert.AreEqual("Sally", ((TestObject) o).Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeDictionary()
|
||||
{
|
||||
@@ -82,6 +109,18 @@ namespace Spring.Objects.Factory.Xml
|
||||
Assert.AreEqual("Eva", map["Juergen"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeMapWithInnerObjectAsMapEntryValue()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithMapOfRefs");
|
||||
IDictionary map = to.SomeMap;
|
||||
Assert.NotNull(map);
|
||||
Assert.AreEqual(2, map.Count);
|
||||
Assert.NotNull(map["Rob"]);
|
||||
Assert.That(map["Rob"], Is.InstanceOf(typeof(TestObject)));
|
||||
Assert.AreEqual("Sally", ((TestObject) map["Rob"]).Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeNameValueCollection()
|
||||
{
|
||||
@@ -92,5 +131,89 @@ namespace Spring.Objects.Factory.Xml
|
||||
Assert.AreEqual("Kerry", map["Rod"]);
|
||||
Assert.AreEqual("Eva", map["Juergen"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeListInConstructor()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithListInConstructor");
|
||||
IList list = to.SomeList;
|
||||
Assert.AreEqual(3, list.Count);
|
||||
Assert.AreEqual("Rob Harrop", list[0]);
|
||||
Assert.AreEqual("Rod Johnson", list[1]);
|
||||
Assert.AreEqual("Juergen Hoeller", list[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeListWithInnerObjectAsListElementInConstructor()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithListOfRefsInConstructor");
|
||||
IList list = to.SomeList;
|
||||
Assert.IsNotNull(list);
|
||||
Assert.AreEqual(3, list.Count);
|
||||
Assert.IsNotNull(list[2]);
|
||||
Assert.That(list[2], Is.InstanceOf(typeof(TestObject)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeSetInConstructor()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithSetInConstructor");
|
||||
ISet set = to.SomeSet;
|
||||
Assert.AreEqual(2, set.Count);
|
||||
Assert.IsTrue(set.Contains("Rob Harrop"));
|
||||
Assert.IsTrue(set.Contains("Sally Greenwood"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeSetWithInnerObjectAsSetElementInConstructor()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithSetOfRefsInConstructor");
|
||||
ISet set = to.SomeSet;
|
||||
Assert.IsNotNull(set);
|
||||
Assert.AreEqual(2, set.Count);
|
||||
IEnumerator enumerator = set.GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
enumerator.MoveNext();
|
||||
object o = enumerator.Current;
|
||||
Assert.IsNotNull(o);
|
||||
Assert.That(o, Is.InstanceOf(typeof(TestObject)));
|
||||
Assert.AreEqual("Sally", ((TestObject)o).Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeMapInConstructor()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithMapInConstructor");
|
||||
IDictionary map = to.SomeMap;
|
||||
Assert.AreEqual(3, map.Count);
|
||||
Assert.AreEqual("Sally", map["Rob"]);
|
||||
Assert.AreEqual("Kerry", map["Rod"]);
|
||||
Assert.AreEqual("Eva", map["Juergen"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeMapWithInnerObjectgAsMapEntryValueInConstructor()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithMapOfRefsInConstructor");
|
||||
IDictionary map = to.SomeMap;
|
||||
Assert.IsNotNull(map);
|
||||
Assert.AreEqual(2, map.Count);
|
||||
Assert.IsNotNull(map["Rob"]);
|
||||
Assert.That(map["Rob"], Is.InstanceOf(typeof(TestObject)));
|
||||
Assert.AreEqual("Sally", ((TestObject) map["Rob"]).Name);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeNameValueCollectionInConstructor()
|
||||
{
|
||||
TestObject to = (TestObject)this.objectFactory.GetObject("childWithPropsInConstructor");
|
||||
NameValueCollection props = to.SomeNameValueCollection;
|
||||
Assert.AreEqual(3, props.Count);
|
||||
Assert.AreEqual("Sally", props["Rob"]);
|
||||
Assert.AreEqual("Kerry", props["Rod"]);
|
||||
Assert.AreEqual("Eva", props["Juergen"]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if !NET_1_1
|
||||
using System.Collections.Specialized;
|
||||
#endif
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design.Serialization;
|
||||
using System.Drawing;
|
||||
@@ -242,7 +245,7 @@ namespace Spring.Objects
|
||||
get { return computers; }
|
||||
}
|
||||
|
||||
public virtual Set SomeSet
|
||||
public virtual ISet SomeSet
|
||||
{
|
||||
get { return someSet; }
|
||||
set { this.someSet = value; }
|
||||
@@ -266,6 +269,14 @@ namespace Spring.Objects
|
||||
set { this.someList = value;}
|
||||
}
|
||||
|
||||
#if !NET_1_1
|
||||
public virtual List<string> SomeGenericStringList
|
||||
{
|
||||
get { return someGenericStringList; }
|
||||
set { this.someGenericStringList = value; }
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual NameValueCollection SomeNameValueCollection
|
||||
{
|
||||
get { return someNameValueCollection; }
|
||||
@@ -370,8 +381,8 @@ namespace Spring.Objects
|
||||
};
|
||||
|
||||
private Type classProperty;
|
||||
private Set computers = new HybridSet();
|
||||
private Set someSet = new HybridSet();
|
||||
private ISet computers = new HybridSet();
|
||||
private ISet someSet = new HybridSet();
|
||||
private IDictionary someMap = new Hashtable();
|
||||
private IList someList = new ArrayList();
|
||||
private DateTime date = DateTime.Now;
|
||||
@@ -397,6 +408,7 @@ namespace Spring.Objects
|
||||
|
||||
private IDictionary sharedState;
|
||||
private NameValueCollection someNameValueCollection;
|
||||
private List<string> someGenericStringList;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -432,6 +444,26 @@ namespace Spring.Objects
|
||||
this.spouse = spouse;
|
||||
}
|
||||
|
||||
public TestObject(IList someList)
|
||||
{
|
||||
this.someList = someList;
|
||||
}
|
||||
|
||||
public TestObject(ISet someSet)
|
||||
{
|
||||
this.someSet = someSet;
|
||||
}
|
||||
|
||||
public TestObject(IDictionary someMap)
|
||||
{
|
||||
this.someMap = someMap;
|
||||
}
|
||||
|
||||
public TestObject(NameValueCollection someProps)
|
||||
{
|
||||
this.someNameValueCollection = someProps;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
|
||||
@@ -338,6 +338,7 @@
|
||||
<Compile Include="Objects\Factory\Support\ObjectDefinitionBuilderTests.cs" />
|
||||
<Compile Include="Objects\Factory\Xml\ArrayCtorDependencyObject.cs" />
|
||||
<Compile Include="Objects\Factory\Xml\CollectionMergingTests.cs" />
|
||||
<Compile Include="Objects\Factory\Xml\CollectionMergingGenericTests.cs" />
|
||||
<Compile Include="Objects\Factory\Xml\LocaleTests.cs" />
|
||||
<Compile Include="Objects\Factory\Xml\NamespaceParserRegistryTests.cs" />
|
||||
<Compile Include="Objects\Factory\Xml\ObjectFactorySectionHandlerTests.cs" />
|
||||
@@ -811,6 +812,7 @@
|
||||
<Content Include="Data\Spring\Objects\Factory\Xml\constructor-arg.xml" />
|
||||
<Content Include="Data\Spring\Objects\Factory\Xml\array-autowire.xml" />
|
||||
<Content Include="Data\Spring\Objects\Factory\Xml\collectionMerging.xml" />
|
||||
<Content Include="Data\Spring\Objects\Factory\Xml\collectionMergingGeneric.xml" />
|
||||
<Content Include="Data\Spring\Objects\Factory\Xml\objectNameGeneration.xml" />
|
||||
<Content Include="Data\Spring\Objects\Factory\Xml\simple-constructor-arg.xml" />
|
||||
<Content Include="Data\Spring\Objects\Factory\Xml\expressions.xml" />
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
<File
|
||||
RelPath = "Data\Spring\Objects\Factory\Support\TestForm.aspx.cs"
|
||||
DependentUpon = "TestForm.aspx"
|
||||
SubType = "ASPXCodeBehind"
|
||||
SubType = "Code"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
@@ -321,7 +321,7 @@
|
||||
/>
|
||||
<File
|
||||
RelPath = "Web\Support\ControlInterceptionTests.cs"
|
||||
SubType = "ASPXCodeBehind"
|
||||
SubType = "Code"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
|
||||
Reference in New Issue
Block a user