Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPRNET-1507 Add support for dynamic type ExpandoObject in spring.net expressions #21

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

namespace Spring.Expressions
{
using System.Collections.Generic;

/// <summary>
/// Represents node that navigates to object's property or public field.
/// </summary>
Expand Down Expand Up @@ -87,8 +89,17 @@ private void InitializeNode(object context)
// initialize this node if necessary
if (contextType != null && accessor == null)
{
// try to initialize node as ExpandoObject value
#if NET_4_0
if (contextType == typeof(System.Dynamic.ExpandoObject))
#else
if(context.ToString() == "System.Dynamic.ExpandoObject")
#endif
{
accessor = new ExpandoObjectValueAccessor(memberName);
}
// try to initialize node as enum value first
if (contextType.IsEnum)
else if (contextType.IsEnum)
{
try
{
Expand All @@ -102,6 +113,7 @@ private void InitializeNode(object context)
}
}


// then try to initialize node as property or field value
if (accessor == null)
{
Expand Down Expand Up @@ -695,6 +707,42 @@ public override void Set(object context, object value)

#endregion

#region ExpandoObjectValueAccessor implementation

private class ExpandoObjectValueAccessor : BaseValueAccessor
{
private string memberName;

public ExpandoObjectValueAccessor(string memberName)
{
this.memberName = memberName;
}

public override object Get(object context)
{
var dictionary = context as IDictionary<string, object>;

object value;
if (dictionary.TryGetValue(memberName, out value))
return value;
#if NET_4_0
throw new InvalidPropertyException(typeof(System.Dynamic.ExpandoObject), memberName,
"'" + memberName +
"' node cannot be resolved for the specified context [" +
context + "].");
#else
throw new InvalidPropertyException("'" + memberName + "' node cannot be resolved for the specified context [" + context + "].");
#endif
}

public override void Set(object context, object value)
{
throw new NotSupportedException("Cannot set the value of an expando object.");
}
}

#endregion

#region TypeValueAccessor implementation

private class TypeValueAccessor : BaseValueAccessor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,40 @@ public void TestMixedAddition()
object value = ExpressionEvaluator.GetValue(null, "'123' + 1");
Assert.AreEqual("1231", value);
}

[Test(Description="SPRNET-944")]
#if NET_4_0
[Test(Description = "SPRNET-1507 - Test 1")]
public void TestExpandoObject()
{
dynamic dynamicObject = new System.Dynamic.ExpandoObject();
//add property at run-time
dynamicObject.IssueId = "1507";

object value = ExpressionEvaluator.GetValue(dynamicObject, "IssueId");
Assert.AreEqual("1507", value);
}

[Test(Description = "SPRNET-1507 - Test 2")]
public void TestExpandoObjectWithNotExistedProperty()
{
try
{
dynamic dynamicObject = new System.Dynamic.ExpandoObject();

ExpressionEvaluator.GetValue(dynamicObject, "PropertyName");
Assert.Fail();
}
catch (InvalidPropertyException ex)
{
Assert.AreEqual(
"'PropertyName' node cannot be resolved for the specified context [System.Dynamic.ExpandoObject].",
ex.Message);
}
}
#endif
[Test(Description = "SPRNET-944")]
public void DateTests()
{
string dateLiteral = (string)ExpressionEvaluator.GetValue(null, "'date'");
string dateLiteral = (string)ExpressionEvaluator.GetValue(null, "'date'");
Assert.AreEqual("date", dateLiteral);
}

Expand Down Expand Up @@ -321,7 +350,7 @@ public void ThrowsSyntaxErrorException()
}
catch (RecognitionException ex)
{
Assert.AreEqual("Syntax Error on line 1, column 6: expecting ''', found '<EOF>' in expression"+Environment.NewLine+"''date'", ex.Message);
Assert.AreEqual("Syntax Error on line 1, column 6: expecting ''', found '<EOF>' in expression" + Environment.NewLine + "''date'", ex.Message);
}
}

Expand Down Expand Up @@ -756,8 +785,8 @@ public void TestTypeNodeWithAssemblyQualifiedName()
[Test]
public void TestTypeNodeWithGenericAssemblyQualifiedName()
{
// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[System.Int32], mscorlib)"));
// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[System.Int32, mscorlib]], mscorlib)"));
// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[System.Int32], mscorlib)"));
// Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[System.Int32, mscorlib]], mscorlib)"));
Assert.AreEqual(typeof(int?), ExpressionEvaluator.GetValue(null, "T(System.Nullable`1[[int]], mscorlib)"));
Assert.AreEqual(typeof(System.Collections.Generic.Dictionary<string, bool>), ExpressionEvaluator.GetValue(null, "T(System.Collections.Generic.Dictionary`2[System.String,System.Boolean],mscorlib)"));
}
Expand Down Expand Up @@ -973,8 +1002,8 @@ public void TestLogicalOrOperator()
[Test]
public void TestBitwiseOrOperator()
{
Assert.AreEqual( 1 | 2, ExpressionEvaluator.GetValue(null, "1 or 2"));
Assert.AreEqual( 1 | -2, ExpressionEvaluator.GetValue(null, "1 or -2"));
Assert.AreEqual(1 | 2, ExpressionEvaluator.GetValue(null, "1 or 2"));
Assert.AreEqual(1 | -2, ExpressionEvaluator.GetValue(null, "1 or -2"));
Assert.AreEqual(RegexOptions.IgnoreCase | RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase or T(System.Text.RegularExpressions.RegexOptions).Compiled"));
}

Expand All @@ -1001,7 +1030,7 @@ public void TestBitwiseAndOperator()
Assert.AreEqual(1 & 3, ExpressionEvaluator.GetValue(null, "1 and 3"));
Assert.AreEqual(1 & -1, ExpressionEvaluator.GetValue(null, "1 and -1"));
Hashtable vars = new Hashtable();
vars["ALL"] = (RegexOptions) 0xFFFF;
vars["ALL"] = (RegexOptions)0xFFFF;
Assert.AreEqual(RegexOptions.IgnoreCase, ExpressionEvaluator.GetValue(null, "T(System.Text.RegularExpressions.RegexOptions).IgnoreCase and #ALL", vars));
}

Expand All @@ -1015,7 +1044,7 @@ public void TestLogicalNotOperator()
Assert.IsTrue((bool)ExpressionEvaluator.GetValue(null, "!false"));
string expression = @"IsMember('Nikola Tesla') and !IsMember('Mihajlo Pupin')";
Assert.IsFalse((bool)ExpressionEvaluator.GetValue(ieee, expression));
Assert.AreEqual( ~RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "!T(System.Text.RegularExpressions.RegexOptions).Compiled"));
Assert.AreEqual(~RegexOptions.Compiled, ExpressionEvaluator.GetValue(null, "!T(System.Text.RegularExpressions.RegexOptions).Compiled"));
}

/// <summary>
Expand Down Expand Up @@ -1679,8 +1708,8 @@ public void TestQualifiedNameMayContainDotsAndSlashes()

Assert.AreEqual(typeof(TestObject),
ExpressionEvaluator.GetValue(null, @"@(my.Context/bla\:goran)").GetType());
// Assert.AreEqual(typeof(TestObject),
// ExpressionEvaluator.GetValue(null, "@(my\\.Context:goran)").GetType());
// Assert.AreEqual(typeof(TestObject),
// ExpressionEvaluator.GetValue(null, "@(my\\.Context:goran)").GetType());
}

/// <summary>
Expand Down Expand Up @@ -1721,14 +1750,14 @@ public void TestDelegateFunctionExpressions()

vars = new Hashtable();
vars["max"] = new DoubleFunctionTwoArgs(Max);
result = (double) ExpressionEvaluator.GetValue(null, "#max(5,25)", vars);
result = (double)ExpressionEvaluator.GetValue(null, "#max(5,25)", vars);
Assert.AreEqual(25, result);


}

private delegate double DoubleFunction(double arg);

private double Sqrt(double arg)
{
return Math.Sqrt(arg);
Expand Down Expand Up @@ -1826,7 +1855,7 @@ public object Process(ICollection source, object[] args)
if ((int)item % 2 == 0)
{
total = NumberUtils.Add(total, item);
}
}
}
else
{
Expand Down Expand Up @@ -1967,7 +1996,7 @@ public void TestSortProcessor()
Assert.AreEqual(new int[] { 6, 8, 14, 24 }, ExpressionEvaluator.GetValue(set, "sort()"));
}

[Test(Description="sort supports any ICollection containing elements of uniform type")]
[Test(Description = "sort supports any ICollection containing elements of uniform type")]
public void TestSortProcessorWithSimpleICollectionType()
{
Stack stack = new Stack(new int[] { 24, 8, 14, 6 });
Expand Down Expand Up @@ -2019,8 +2048,8 @@ public void TestDistinctProcessorWithInvalidNumberOfArguments()
public void TestConversionProcessor()
{
object[] arr = new object[] { "0", 1, 1.1m, "1.1", 1.1f };
decimal[] result = (decimal[]) ExpressionEvaluator.GetValue(arr, "convert(decimal)");
Assert.AreEqual( 0.0m, result[0] );
decimal[] result = (decimal[])ExpressionEvaluator.GetValue(arr, "convert(decimal)");
Assert.AreEqual(0.0m, result[0]);
Assert.AreEqual(1.0m, result[1]);
Assert.AreEqual(1.1m, result[2]);
Assert.AreEqual(1.1m, result[3]);
Expand All @@ -2031,7 +2060,7 @@ public void TestConversionProcessor()
public void TestReverseProcessor()
{
object[] arr = new object[] { "0", 1, 2.1m, "3", 4.1f };
object[] result = new ArrayList( (ICollection) ExpressionEvaluator.GetValue(arr, "reverse()") ).ToArray();
object[] result = new ArrayList((ICollection)ExpressionEvaluator.GetValue(arr, "reverse()")).ToArray();
Assert.AreEqual(new object[] { 4.1f, "3", 2.1m, 1, "0" }, result);
}

Expand Down Expand Up @@ -2976,7 +3005,8 @@ internal class Foo
private Nullable<DateTime> nullableDate;
private Nullable<Int32> nullableInt;

public Foo() : this(FooType.One)
public Foo()
: this(FooType.One)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Common.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="nunit.framework, Version=2.2.5.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\nunit.framework.dll</HintPath>
Expand Down