Support type alias resolution in <value/> element [SPRNET-1119]

This commit is contained in:
bbaia
2010-04-08 16:19:02 +00:00
parent 4dc026d2e6
commit cb776d4098
6 changed files with 267 additions and 134 deletions

View File

@@ -21,122 +21,193 @@
#region Imports
using System;
using Spring.Util;
#endregion
namespace Spring.Objects.Factory.Config
{
/// <summary>
/// Holder for a typed <see cref="System.String"/> value.
/// </summary>
/// <remarks>
/// <p>
/// Can be added to object definitions to explicitly specify
/// a target type for a <see cref="System.String"/> value,
/// for example for collection
/// elements.
/// </p>
/// <p>
/// This holder just stores the <see cref="System.String"/> value and the target
/// <see cref="System.Type"/>. The actual conversion will be performed by
/// the surrounding object factory.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Rick Evans (.NET)</author>
[Serializable]
public class TypedStringValue
{
#region Constructor (s) / Destructor
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Config.TypedStringValue"/>
/// class.
/// </summary>
public TypedStringValue()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TypedStringValue"/> class.
/// </summary>
/// <param name="value">The value.</param>
public TypedStringValue(string value)
{
Value = value;
}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Config.TypedStringValue"/>
/// class.
/// </summary>
/// <param name="value">
/// The value that is to be converted.
/// </param>
/// <param name="targetType">
/// The <see cref="System.Type"/> to convert to.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="targetType"/> is
/// <see langword="null"/>.
/// </exception>
public TypedStringValue(string value, Type targetType)
{
Value = value;
TargetType = targetType;
}
#endregion
/// <summary>
/// The value that is to be converted.
/// </summary>
/// <remarks>
/// <p>
/// Obviously if the
/// <see cref="Spring.Objects.Factory.Config.TypedStringValue.TargetType"/>
/// is the <see cref="System.String"/> <see cref="System.Type"/>, no conversion
/// will actually be performed.
/// </p>
/// </remarks>
public string Value
{
get { return theValue; }
set { this.theValue = value; }
}
/// <summary>
/// The <see cref="System.Type"/> to convert to.
/// </summary>
/// <exception cref="System.ArgumentNullException">
/// If the setter is supplied with a <see langword="null"/> value.
/// </exception>
public Type TargetType
{
get { return targetType; }
set
{
AssertUtils.ArgumentNotNull(value, "TargetType");
targetType = value;
}
}
/// <summary>
/// Gets a value indicating whether this instance has target type.
/// </summary>
/// <value>
/// <c>true</c> if this instance has target type; otherwise, <c>false</c>.
/// </value>
public bool HasTargetType
{
get { return targetType != null; }
}
private string theValue;
private Type targetType;
}
using Spring.Util;
using Spring.Core.TypeResolution;
#endregion
namespace Spring.Objects.Factory.Config
{
/// <summary>
/// Holder for a typed <see cref="System.String"/> value.
/// </summary>
/// <remarks>
/// <p>
/// Can be added to object definitions to explicitly specify
/// a target type for a <see cref="System.String"/> value,
/// for example for collection
/// elements.
/// </p>
/// <p>
/// This holder just stores the <see cref="System.String"/> value and the target
/// <see cref="System.Type"/>. The actual conversion will be performed by
/// the surrounding object factory.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Rick Evans (.NET)</author>
/// <author>Bruno Baia (.NET)</author>
[Serializable]
public class TypedStringValue
{
private string theValue;
private object targetType;
#region Constructor (s) / Destructor
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Config.TypedStringValue"/>
/// class.
/// </summary>
public TypedStringValue()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TypedStringValue"/> class.
/// </summary>
/// <param name="value">The value.</param>
public TypedStringValue(string value)
{
Value = value;
}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Config.TypedStringValue"/>
/// class.
/// </summary>
/// <param name="value">
/// The value that is to be converted.
/// </param>
/// <param name="targetType">
/// The <see cref="System.Type"/> to convert to.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="targetType"/> is
/// <see langword="null"/>.
/// </exception>
public TypedStringValue(string value, Type targetType)
{
Value = value;
TargetType = targetType;
}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Config.TypedStringValue"/>
/// class.
/// </summary>
/// <param name="value">
/// The value that is to be converted.
/// </param>
/// <param name="targetTypeName">
/// The unresolved type to convert to.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="targetTypeName"/> is a
/// <see langword="null"/> or an empty string.
/// </exception>
public TypedStringValue(string value, string targetTypeName)
{
Value = value;
TargetTypeName = targetTypeName;
}
#endregion
/// <summary>
/// The value that is to be converted.
/// </summary>
/// <remarks>
/// <p>
/// Obviously if the
/// <see cref="Spring.Objects.Factory.Config.TypedStringValue.TargetType"/>
/// is the <see cref="System.String"/> <see cref="System.Type"/>, no conversion
/// will actually be performed.
/// </p>
/// </remarks>
public string Value
{
get { return theValue; }
set { this.theValue = value; }
}
/// <summary>
/// The <see cref="System.Type"/> to convert to.
/// </summary>
/// <exception cref="System.ArgumentNullException">
/// If the setter is supplied with a <see langword="null"/> value.
/// </exception>
public Type TargetType
{
get
{
if (!HasTargetType)
{
throw new ApplicationException(
"Typed String value does not carry a resolved System.Type");
}
return (Type)targetType;
}
set
{
AssertUtils.ArgumentNotNull(value, "TargetType");
targetType = value;
}
}
/// <summary>
/// The unresolved type to convert to.
/// </summary>
/// <exception cref="System.ArgumentNullException">
/// If the setter is supplied with a <see langword="null"/> value or an empty string.
/// </exception>
public string TargetTypeName
{
get
{
if (targetType is Type)
{
return ((Type) targetType).FullName;
}
else
{
return targetType as string;
}
}
set
{
AssertUtils.ArgumentHasText(value, "TargetTypeName");
targetType = value;
}
}
/// <summary>
/// Gets a value indicating whether this instance has target type.
/// </summary>
/// <value>
/// <c>true</c> if this instance has target type; otherwise, <c>false</c>.
/// </value>
public bool HasTargetType
{
get { return targetType is Type; }
}
/// <summary>
/// Determine the type to convert to, resolving it from a specified type name if necessary.
/// </summary>
/// <returns>The resolved type to convert to.</returns>
public Type ResolveTargetType()
{
if (this.targetType == null)
{
return null;
}
Type resolvedType = TypeResolutionUtils.ResolveType(this.TargetTypeName);
this.targetType = resolvedType;
return resolvedType;
}
}
}

View File

@@ -239,14 +239,11 @@ namespace Spring.Objects.Factory.Support
/// <returns>The resolved target type, if any. <see lang="null" /> otherwise.</returns>
protected virtual Type ResolveTargetType(TypedStringValue value)
{
if (value.HasTargetType)
if (value.HasTargetType)
{
return value.TargetType;
}
else
{
return null;
return value.TargetType;
}
return value.ResolveTargetType();
}
/// <summary>

View File

@@ -1003,15 +1003,7 @@ namespace Spring.Objects.Factory.Xml
}
else
{
Type resolvedValueType = TypeResolutionUtils.ResolveType(valueType);
if (resolvedValueType == typeof(string))
{
return ParseTextValueElement(element, name);
}
else
{
return new TypedStringValue(ParseTextValueElement(element, name), resolvedValueType);
}
return new TypedStringValue(ParseTextValueElement(element, name), valueType);
}
}

View File

@@ -5,6 +5,7 @@
<property name="TypeAliases">
<dictionary>
<entry key="TestObject" value="Spring.Objects.TestObject, Spring.Core.Tests" />
<entry key="intAlias" value="System.Int32" />
</dictionary>
</property>
</object>
@@ -19,4 +20,12 @@
<constructor-arg name="age" value="26"/>
</object>
<!-- SPRNET-1119 -->
<object id="testObject4" type="TestObject">
<constructor-arg name="name" value="Bruno"/>
<constructor-arg name="age">
<value type="intAlias">30</value>
</constructor-arg>
</object>
</objects>

View File

@@ -124,6 +124,13 @@ namespace Spring.Objects.Factory.Config
Assert.AreEqual(typeof(TestObject), obj3.GetType());
Assert.AreEqual("Bruno", ((TestObject)obj3).Name);
Assert.AreEqual(26, ((TestObject)obj3).Age);
// SPRNET-1119
object obj4 = ctx.GetObject("testObject4");
Assert.IsNotNull(obj4);
Assert.AreEqual(typeof(TestObject), obj4.GetType());
Assert.AreEqual("Bruno", ((TestObject)obj4).Name);
Assert.AreEqual(30, ((TestObject)obj4).Age);
}
private void CreateConfigurerAndTestLinkedList(IDictionary typeAliases)

View File

@@ -40,20 +40,41 @@ namespace Spring.Objects.Factory.Config
public void Instantiation()
{
string expectedNow = DateTime.Now.ToShortDateString();
TypedStringValue tsv = new TypedStringValue(expectedNow, typeof (DateTime));
TypedStringValue tsv = new TypedStringValue(expectedNow, typeof (DateTime));
Assert.AreEqual(expectedNow, tsv.Value);
Assert.AreEqual(typeof (DateTime), tsv.TargetType);
tsv = new TypedStringValue(expectedNow);
Assert.AreEqual(expectedNow, tsv.Value);
tsv = new TypedStringValue(expectedNow, typeof(DateTime).FullName);
Assert.AreEqual(expectedNow, tsv.Value);
Assert.AreEqual(typeof(DateTime).FullName, tsv.TargetTypeName);
}
[Test]
[ExpectedException(typeof (ArgumentNullException))]
public void InstantiationWithNullType()
{
new TypedStringValue(string.Empty, null);
new TypedStringValue(string.Empty, (Type)null);
}
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void InstantiationWithNullTypeName()
{
new TypedStringValue(string.Empty, (string)null);
}
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void InstantiationWithEmptyTypeName()
{
new TypedStringValue(string.Empty, " ");
}
[Test]
[ExpectedException(typeof (ArgumentNullException))]
public void SetTargetTypePropertyToNullType()
@@ -62,6 +83,14 @@ namespace Spring.Objects.Factory.Config
tsv.TargetType = null;
}
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void SetTargetTypeNamePropertyToEmptyString()
{
TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime));
tsv.TargetTypeName = " ";
}
[Test]
public void IsSerializable()
{
@@ -88,5 +117,33 @@ namespace Spring.Objects.Factory.Config
Assert.AreEqual(expectedValue, deser.Value,
"Serialization roundtrip yielded the wrong Value.");
}
[Test]
public void HasTargetType()
{
TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime));
Assert.IsTrue(tsv.HasTargetType);
}
[Test]
public void HasTargetTypeReturnsFalseWhenTargetTypeNotResolved()
{
TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime).FullName);
Assert.IsFalse(tsv.HasTargetType);
tsv = new TypedStringValue(string.Empty, typeof(DateTime));
Assert.IsTrue(tsv.HasTargetType);
tsv.TargetTypeName = typeof(DateTime).FullName;
Assert.IsFalse(tsv.HasTargetType);
}
[Test]
public void ResolveTargetType()
{
TypedStringValue tsv = new TypedStringValue(string.Empty, typeof(DateTime).FullName);
Assert.IsFalse(tsv.HasTargetType);
Assert.AreEqual(typeof(DateTime), tsv.ResolveTargetType());
Assert.IsTrue(tsv.HasTargetType);
}
}
}