SPRNET-1242 added support for collection property merging of Set<T> and List<T>

This commit is contained in:
sbohlen
2011-05-13 00:15:26 +00:00
parent 5a5f5a92ab
commit f605067636
4 changed files with 108 additions and 12 deletions

View File

@@ -22,8 +22,11 @@
using System;
using System.Collections;
using System.ComponentModel;
#if NET_2_0
using System.Collections.Generic;
#endif
using System.ComponentModel;
using Spring.Util;
#endregion
@@ -65,18 +68,18 @@ namespace Spring.Core.TypeConversion
Type componentType = requiredType.GetElementType();
if (newValue is ICollection)
{
ICollection elements = (ICollection) newValue;
ICollection elements = (ICollection)newValue;
return ToArrayWithTypeConversion(componentType, elements, propertyName);
}
else if (newValue is string)
{
if (requiredType.Equals(typeof(char[])))
{
return ((string) newValue).ToCharArray();
return ((string)newValue).ToCharArray();
}
else
{
string[] elements = StringUtils.CommaDelimitedListToStringArray((string) newValue);
string[] elements = StringUtils.CommaDelimitedListToStringArray((string)newValue);
return ToArrayWithTypeConversion(componentType, elements, propertyName);
}
}
@@ -89,6 +92,31 @@ namespace Spring.Core.TypeConversion
return result;
}
}
#if NET_2_0
// if required type is some ISet<T>, convert all the elements
if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(Spring.Collections.Generic.ISet<>)))
{
// convert individual elements to array elements
Type componentType = requiredType.GetGenericArguments()[0];
if (newValue is ICollection)
{
ICollection elements = (ICollection)newValue;
return ToTypedCollectionWithTypeConversion(typeof(Spring.Collections.Generic.Set<>), componentType, elements, propertyName);
}
}
// if required type is some IList<T>, convert all the elements
if (requiredType != null && requiredType.IsGenericType && TypeImplementsGenericInterface(requiredType, typeof(IList<>)))
{
// convert individual elements to array elements
Type componentType = requiredType.GetGenericArguments()[0];
if (newValue is ICollection)
{
ICollection elements = (ICollection)newValue;
return ToTypedCollectionWithTypeConversion(typeof(List<>), componentType, elements, propertyName);
}
}
#endif
// try to convert using type converter
try
@@ -118,7 +146,7 @@ namespace Spring.Core.TypeConversion
else
{
// look if it's an enum
if (requiredType != null
if (requiredType != null
&& requiredType.IsEnum
&& (!(newValue is float)
&& (!(newValue is double))))
@@ -145,7 +173,7 @@ namespace Spring.Core.TypeConversion
else
{
throw new TypeMismatchException(
CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType);
CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType);
}
}
}
@@ -156,8 +184,8 @@ namespace Spring.Core.TypeConversion
CreatePropertyChangeEventArgs(propertyName, null, newValue), requiredType, ex);
}
#if NET_2_0
if (newValue == null
&& (requiredType == null
if (newValue == null
&& (requiredType == null
|| !Type.GetType("System.Nullable`1").Equals(requiredType.GetGenericTypeDefinition())))
#else
if (newValue == null)
@@ -183,10 +211,34 @@ namespace Spring.Core.TypeConversion
return destination;
}
#if NET_2_0
private static object ToTypedCollectionWithTypeConversion(Type targetCollectionType, Type componentType, ICollection elements, string propertyName)
{
if (!TypeImplementsGenericInterface(targetCollectionType, typeof(ICollection<>)))
{
throw new ArgumentException("argument must be a type that derives from ICollection<T>", "targetCollectionType");
}
Type collectionType = targetCollectionType.MakeGenericType(new Type[] { componentType });
object typedCollection = Activator.CreateInstance(collectionType);
int i = 0;
foreach (object element in elements)
{
object value = ConvertValueIfNecessary(componentType, element, BuildIndexedPropertyName(propertyName, i));
collectionType.GetMethod("Add").Invoke(typedCollection, new object[] { value });
i++;
}
return typedCollection;
}
#endif
private static string BuildIndexedPropertyName(string propertyName, int index)
{
return (propertyName != null ?
propertyName + "[" + index + "]":
propertyName + "[" + index + "]" :
null);
}
@@ -222,5 +274,41 @@ namespace Spring.Core.TypeConversion
return new PropertyChangeEventArgs(fullPropertyName, oldValue, newValue);
}
#if NET_2_0
/// <summary>
/// Determines if a Type implements a specific generic interface.
/// </summary>
/// <param name="candidateType">Candidate <see lang="Type"/> to evaluate.</param>
/// <param name="matchingInterface">The <see lang="interface"/> to test for in the Candidate <see lang="Type"/>.</param>
/// <returns><see lang="true" /> if a match, else <see lang="false"/></returns>
private static bool TypeImplementsGenericInterface(Type candidateType, Type matchingInterface)
{
if (!matchingInterface.IsInterface)
{
throw new ArgumentException("matchingInterface Type must be an Interface Type", "matchingInterface");
}
bool match = false;
Type[] implementedInterfaces = candidateType.GetInterfaces();
foreach (Type interfaceType in implementedInterfaces)
{
if (false == interfaceType.IsGenericType)
{
continue;
}
Type genericType = interfaceType.GetGenericTypeDefinition();
if (genericType == matchingInterface)
{
match = true;
break;
}
}
return match;
}
#endif
}
}

View File

@@ -120,7 +120,15 @@
<Compile Include="Collections\DictionarySet.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Collections\Generic\DictionarySet.cs" />
<Compile Include="Collections\Generic\HashedSet.cs" />
<Compile Include="Collections\Generic\ImmutableSet.cs" />
<Compile Include="Collections\Generic\ISet.cs" />
<Compile Include="Collections\Generic\OrderedSet.cs" />
<Compile Include="Collections\Generic\ReadOnlyDictionary.cs" />
<Compile Include="Collections\Generic\Set.cs" />
<Compile Include="Collections\Generic\SortedSet.cs" />
<Compile Include="Collections\Generic\SynchronizedSet.cs" />
<Compile Include="Collections\HashedSet.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -6,7 +6,7 @@
<object id="parentWithList" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="SomeGenericStringList">
<list>
<list element-type="string">
<value>Rob Harrop</value>
<value>Rod Johnson</value>
</list>
@@ -15,7 +15,7 @@
<object id="childWithList" parent="parentWithList">
<property name="SomeGenericStringList">
<list merge="true">
<list element-type="string" merge="true">
<value>Juergen Hoeller</value>
</list>
</property>

View File

@@ -39,7 +39,7 @@ namespace Spring.Objects.Factory.Xml
/// <author>Rick Evans</author>
/// <author>Mark Pollack (.NET)</author>
[TestFixture]
[Ignore("SPRNET-1242 Support for collection merging with generic collections")]
[Description("SPRNET-1242 Support for collection merging with generic collections")]
public class CollectionMergingGenericTests
{
private DefaultListableObjectFactory objectFactory;