Issue Details (XML | Word | Printable)

Key: SPRNET-755
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Erich Eichinger
Reporter: Martin Francisco
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Spring.NET

SpEL method invocation fails if the same expression instance is used with two different context types

Created: 26/Oct/07 01:57 PM   Updated: 20/Mar/08 10:19 AM   Resolved: 20/Mar/08 04:03 AM
Component/s: Spring-NET-CORE
Affects Version/s: 1.1 RC2
Fix Version/s: 1.1.1

Time Tracking:
Not Specified


 Description  « Hide
If an expression is reused with two different context types, the second evaluation fails with a

System.Reflection.TargetException : Object does not match target type.

Here's a test to reproduce the problem.

[Test]
public void TestMethodEvaluationOnDifferentContext()
{
    IExpression expression = Expression.Parse("ToString('dummy', null)");
    Assert.AreEqual("dummy", expression.GetValue(0m, null));
    Assert.AreEqual("dummy", expression.GetValue(0, null));
}

It looks like the MethodNode is caching the MethodInfo from the first evaluation and using it to invoke on the second evaluation.


Erich Eichinger added a comment - 06/Mar/08 01:27 PM
The same problem applies to invoking the expression using different argument types:

[Test]
public void TestMethodEvaluationOnDifferentArgumentTypes()
{
  IExpression expression = Expression.Parse("Foo(#var1)");
  MethodInvokationCases testContext = new MethodInvokationCases();
  Hashtable args = new Hashtable();
  args["var1"] = "myString";
  Assert.AreEqual("myString", expression.GetValue(testContext, args));
  args["var1"] = 12;
  Assert.AreEqual(12, expression.GetValue(testContext, args));
}

class MethodInvokationCases
{
    public string Foo(string stringArg) { return stringArg; }
    public int Foo(int intArg) { return intArg; }
}


This means we not only must throw away the cached SafeMethod instance in case of different target types, but also in case of different argument types.

Erich Eichinger added a comment - 06/Mar/08 02:22 PM
committed a fix that calculates a checksum hash over target-type + argument types and throws away cached method reference in case the checksums don't match.

It still needs some performance testing!

Erich Eichinger added a comment - 20/Mar/08 04:03 AM
just made a performance comparison and added MethodNodeTests.PerformanceOfMethodEvaluationOnDifferentContextTypes()

Expression: "ToString('dummy', CultureInfo.InvariantCulture)"
Runs: 10.000.000

Duration with hash-checking of arguments: 8.4s
Duration without hash-checking arguments: 7.5s

of course when it comes to really switching context, throwing away the cache and reparsing the methodnode gets expensive.

Mark Pollack added a comment - 20/Mar/08 09:12 AM
Around ~10% slow down. I'm curious Martin, what is your reason for not using ExpressionEvaluator.GetValue?

Martin Francisco added a comment - 20/Mar/08 10:19 AM
In my scenario I had a validator that checks if a value is contained in a collection returned by a business layer method. The method returns an ICollection<DomainObject> which can be an empty array, a List<DomainObject>, or even a decorated collection depending on the context. The collection is passed to the validator as a parameter to test that it contains the value of a property on the current context.

Test Expression: #collection.Contains(SomeProperty)

Since the actual concrete collection may be different, the validator test expression can fail when it tries to evaluate the Contains method.