diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs index c316083c..b0ec3266 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs @@ -122,22 +122,19 @@ namespace Spring.Objects.Factory /// The array of object names, or an empty array if none. public static string[] ObjectNamesIncludingAncestors(IListableObjectFactory factory) { - Set result = new HashedSet(); - result.AddAll(factory.GetObjectDefinitionNames()); + ArrayList result = new ArrayList(); + result.AddRange(factory.GetObjectDefinitionNames()); IListableObjectFactory pof = GetParentFactoryIfAny(factory); if (pof != null) { string[] parentsResult = ObjectNamesIncludingAncestors(pof); - result.AddAll(parentsResult); + foreach (string s in parentsResult) + { + if (!result.Contains(s)) result.Add(s); + } } - return ToArrayOfObjectNames(result); - } - - private static string[] ToArrayOfObjectNames(Set result) - { - Array resultArray = Array.CreateInstance(typeof (string), result.Count); - result.CopyTo(resultArray, 0); - return (string[]) resultArray; + //return ToArrayOfObjectNames(result); + return (string[]) result.ToArray(typeof (string)); } /// @@ -179,15 +176,21 @@ namespace Spring.Objects.Factory IListableObjectFactory factory, Type type, bool includePrototypes, bool includeFactoryObjects) { - Set result = new HashedSet(); - result.AddAll(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects)); + ArrayList result = new ArrayList(); + result.AddRange(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects)); IListableObjectFactory pof = GetParentFactoryIfAny(factory); if (pof != null) { string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects); - result.AddAll(parentsResult); + foreach(string s in parentsResult) + { + if (!result.Contains(s)) + { + result.Add(s); + } + } } - return ToArrayOfObjectNames(result); + return (string[]) result.ToArray(typeof (string)); } /// @@ -221,15 +224,21 @@ namespace Spring.Objects.Factory public static string[] ObjectNamesForTypeIncludingAncestors( IListableObjectFactory factory, Type type) { - Set result = new HashedSet(); - result.AddAll(factory.GetObjectNamesForType(type)); + ArrayList result = new ArrayList(); + result.AddRange(factory.GetObjectNamesForType(type)); IListableObjectFactory pof = GetParentFactoryIfAny(factory); if (pof != null) { string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type); - result.AddAll(parentsResult); + foreach(string s in parentsResult) + { + if (!result.Contains(s)) + { + result.Add(s); + } + } } - return ToArrayOfObjectNames(result); + return (string[]) result.ToArray(typeof (string)); } private static IListableObjectFactory GetParentFactoryIfAny(IListableObjectFactory factory) diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index 0cbd2ec1..1adbf103 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -140,6 +140,7 @@ namespace Spring.Objects.Factory.Support { this.log = LogManager.GetLogger( this.GetType() ); this.caseSensitive = caseSensitive; +#if NET_1_0 || NET_1_1 if (caseSensitive) { this.aliasMap = new Hashtable(); @@ -152,6 +153,12 @@ namespace Spring.Objects.Factory.Support this.singletonCache = new CaseInsensitiveHashtable(); this.singletonsInCreation = new CaseInsensitiveHashtable(); } +#else + IEqualityComparer comparer = (caseSensitive) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; + this.aliasMap = new OrderedDictionary(comparer); + this.singletonCache = new OrderedDictionary(comparer); + this.singletonsInCreation = new OrderedDictionary(comparer); +#endif } /// @@ -1253,7 +1260,8 @@ namespace Spring.Objects.Factory.Support { lock (singletonCache) { - return (string[])new ArrayList( singletonCache.Keys ).ToArray( typeof( string ) ); + ICollection keys = singletonCache.Keys; + return (string[])new ArrayList( keys ).ToArray( typeof( string ) ); } } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs index 33bfd7b2..8adda77e 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs @@ -80,7 +80,13 @@ namespace Spring.Objects.Factory protected internal abstract AbstractObjectFactory CreateObjectFactory(bool caseSensitive); - protected AbstractObjectFactory ObjectFactory { get { return CreateObjectFactory(true); } } + private AbstractObjectFactory cachedFactory; + + protected AbstractObjectFactory ObjectFactory + { + get { return cachedFactory; } + set { cachedFactory = value; } + } #endregion @@ -448,6 +454,23 @@ namespace Spring.Objects.Factory .RegisterSingleton(null, DBNull.Value); } + [Test] + public void GetSingletonNamesReflectsOrderOfRegistration() + { + AbstractObjectFactory of; + of = CreateObjectFactory(true); + of.RegisterSingleton("A", new object()); + of.RegisterSingleton("C", new object()); + of.RegisterSingleton("B", new object()); + Assert.AreEqual(new string[] { "A", "C", "B"}, of.GetSingletonNames()); + + of = CreateObjectFactory(false); + of.RegisterSingleton("A", new object()); + of.RegisterSingleton("C", new object()); + of.RegisterSingleton("B", new object()); + Assert.AreEqual(new string[] { "A", "C", "B"}, of.GetSingletonNames(typeof(object))); + } + [Test] [ExpectedException(typeof(ArgumentNullException))] public void ContainsSingletonWithEmptyName() diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs index f955b16b..2b95d7a3 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/ObjectFactoryUtilsTests.cs @@ -23,6 +23,7 @@ using System; using System.Collections; using NUnit.Framework; +using Rhino.Mocks; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; @@ -74,8 +75,28 @@ namespace Spring.Objects.Factory Assert.AreEqual(6, names.Count); } + [Test] + public void ObjectNamesIncludingAncestorsPreserveOrderOfRegistration() + { + MockRepository mocks = new MockRepository(); + IConfigurableListableObjectFactory of = (IConfigurableListableObjectFactory) mocks.DynamicMock(typeof (IConfigurableListableObjectFactory)); + IConfigurableListableObjectFactory ofParent = (IConfigurableListableObjectFactory) mocks.DynamicMock(typeof (IConfigurableListableObjectFactory)); + + using(mocks.Record()) + { + Expect.Call(of.GetObjectDefinitionNames()).Return(new string[] { "objA", "objB", "objC" }); + Expect.Call(((IHierarchicalObjectFactory)of).ParentObjectFactory).Return(ofParent); + Expect.Call(ofParent.GetObjectDefinitionNames()).Return(new string[] { "obj2A", "objB", "obj2C" }); + } + + string[] names = ObjectFactoryUtils.ObjectNamesIncludingAncestors(of); + Assert.AreEqual(5, names.Length); + Assert.AreEqual(new string[] { "objA","objB","objC","obj2A","obj2C" }, names); + mocks.ReplayAll(); + } + [Test] - public void ObjectNamesForType() + public void ObjectNamesForTypeIncludingAncestors() { IList names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(_factory, typeof (ITestObject)); // includes 2 TestObjects from IFactoryObjects (DummyFactory definitions) @@ -86,6 +107,48 @@ namespace Spring.Objects.Factory Assert.IsTrue(names.Contains("testFactory2")); } + [Test] + public void ObjectNamesForTypeIncludingAncestorsPreserveOrderOfRegistration() + { + MockRepository mocks = new MockRepository(); + IConfigurableListableObjectFactory of = (IConfigurableListableObjectFactory)mocks.DynamicMock(typeof(IConfigurableListableObjectFactory)); + IConfigurableListableObjectFactory ofParent = (IConfigurableListableObjectFactory)mocks.DynamicMock(typeof(IConfigurableListableObjectFactory)); + Type EXPECTEDTYPE = typeof (ITestObject); + + using (mocks.Record()) + { + Expect.Call(of.GetObjectNamesForType(EXPECTEDTYPE)).Return(new string[] { "objA", "objB", "objC" }); + Expect.Call(((IHierarchicalObjectFactory)of).ParentObjectFactory).Return(ofParent); + Expect.Call(ofParent.GetObjectNamesForType(EXPECTEDTYPE)).Return(new string[] { "obj2A", "objB", "obj2C" }); + } + + string[] names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(of, EXPECTEDTYPE); + Assert.AreEqual(5, names.Length); + Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); + mocks.ReplayAll(); + } + + [Test] + public void ObjectNamesForTypeIncludingAncestorsPrototypesAndFactoryObjectsPreserveOrderOfRegistration() + { + MockRepository mocks = new MockRepository(); + IConfigurableListableObjectFactory of = (IConfigurableListableObjectFactory)mocks.DynamicMock(typeof(IConfigurableListableObjectFactory)); + IConfigurableListableObjectFactory ofParent = (IConfigurableListableObjectFactory)mocks.DynamicMock(typeof(IConfigurableListableObjectFactory)); + Type EXPECTEDTYPE = typeof(ITestObject); + + using (mocks.Record()) + { + Expect.Call(of.GetObjectNamesForType(EXPECTEDTYPE, false, false)).Return(new string[] { "objA", "objB", "objC" }); + Expect.Call(((IHierarchicalObjectFactory)of).ParentObjectFactory).Return(ofParent); + Expect.Call(ofParent.GetObjectNamesForType(EXPECTEDTYPE, false, false)).Return(new string[] { "obj2A", "objB", "obj2C" }); + } + + string[] names = ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(of, EXPECTEDTYPE, false, false); + Assert.AreEqual(5, names.Length); + Assert.AreEqual(new string[] { "objA", "objB", "objC", "obj2A", "obj2C" }, names); + mocks.ReplayAll(); + } + [Test] public void CountObjectsIncludingAncestorsWithNonHierarchicalFactory() { diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs index a2ff36bd..44abdc76 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs @@ -71,13 +71,11 @@ namespace Spring.Objects.Factory.Xml protected internal override AbstractObjectFactory CreateObjectFactory(bool caseSensitive) { - return (caseSensitive) - ? factory - : new DefaultListableObjectFactory(caseSensitive); + return new DefaultListableObjectFactory(caseSensitive); } private DefaultListableObjectFactory parent; - private XmlObjectFactory factory; +// private XmlObjectFactory factory; #region Test SetUp @@ -100,14 +98,16 @@ namespace Spring.Objects.Factory.Xml UnsupportedObjectDefinitionImplementation unsupportedDefinition = new UnsupportedObjectDefinitionImplementation(); parent.RegisterObjectDefinition("unsupportedDefinition", unsupportedDefinition); - this.factory = new XmlObjectFactory(new ReadOnlyXmlTestResource("test.xml", GetType()), parent); + XmlObjectFactory factory; + factory = new XmlObjectFactory(new ReadOnlyXmlTestResource("test.xml", GetType()), parent); // TODO: should this be allowed? //this.factory.RegisterObjectDefinition("typedfather", new RootObjectDefinition(typeof(object), false)); - this.factory.AddObjectPostProcessor(new AnonymousClassObjectPostProcessor()); - this.factory.AddObjectPostProcessor(new LifecycleObject.PostProcessor()); + factory.AddObjectPostProcessor(new AnonymousClassObjectPostProcessor()); + factory.AddObjectPostProcessor(new LifecycleObject.PostProcessor()); - this.factory.PreInstantiateSingletons(); + factory.PreInstantiateSingletons(); + base.ObjectFactory = factory; } #endregion @@ -166,7 +166,7 @@ namespace Spring.Objects.Factory.Xml [Test] public virtual void CountSingletons() { - Assert.AreEqual(10, factory.GetSingletonCount(), "Number of singletons incorrect"); + Assert.AreEqual(10, ObjectFactory.GetSingletonCount(), "Number of singletons incorrect"); } } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs index f67425b9..9a8ead40 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectFactoryTests.cs @@ -23,6 +23,7 @@ using System; using System.Collections; using System.Data; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Text;