Use 'invocation.Method' as variable for cache attributes key expression resolution [SPRNET-959]

This commit is contained in:
bbaia
2009-12-12 22:41:20 +00:00
parent 6f850cc45c
commit fcfe2ed9b2
4 changed files with 130 additions and 34 deletions

View File

@@ -121,26 +121,33 @@ namespace Spring.Aspects.Cache
CacheParameterInfo cpi = GetCacheParameterInfo(method);
CacheParameterAttribute[][] cacheParameterAttributes = cpi.CacheParameterAttributes;
for (int i = 0; i < cacheParameterAttributes.Length; i++)
{
foreach (CacheParameterAttribute paramInfo in cacheParameterAttributes[i])
{
if (EvalCondition(paramInfo.Condition, paramInfo.ConditionExpression, arguments[i], null))
{
ICache cache = GetCache(paramInfo.CacheName);
object key = paramInfo.KeyExpression.GetValue(arguments[i]);
#region Instrumentation
if (isLogDebugEnabled)
{
logger.Debug(string.Format("Caching parameter for key [{0}] into cache [{1}].", key, paramInfo.CacheName));
}
#endregion
cache.Insert(key, arguments[i], paramInfo.TimeToLiveTimeSpan);
}
}
if (cacheParameterAttributes.Length > 0)
{
IDictionary vars = PrepareVariables(method, arguments);
for (int i = 0; i < cacheParameterAttributes.Length; i++)
{
foreach (CacheParameterAttribute paramInfo in cacheParameterAttributes[i])
{
AssertUtils.ArgumentNotNull(paramInfo.KeyExpression, "Key",
"The cache attribute is missing the key definition.");
if (EvalCondition(paramInfo.Condition, paramInfo.ConditionExpression, arguments[i], vars))
{
ICache cache = GetCache(paramInfo.CacheName);
object key = paramInfo.KeyExpression.GetValue(arguments[i], vars);
#region Instrumentation
if (isLogDebugEnabled)
{
logger.Debug(string.Format("Caching parameter for key [{0}] into cache [{1}].", key, paramInfo.CacheName));
}
#endregion
cache.Insert(key, arguments[i], paramInfo.TimeToLiveTimeSpan);
}
}
}
}
}
}

View File

@@ -118,12 +118,15 @@ namespace Spring.Aspects.Cache
{
CacheResultInfo cacheResultInfo = GetCacheResultInfo(invocation.Method);
// prepare variables for SpEL expressions
IDictionary vars = PrepareVariables(invocation.Method, invocation.Arguments);
bool cacheHit = false;
object returnValue = GetReturnValue(invocation, cacheResultInfo.ResultInfo, out cacheHit);
object returnValue = GetReturnValue(invocation, cacheResultInfo.ResultInfo, vars, out cacheHit);
if (!cacheHit && cacheResultInfo.ItemInfoArray.Length > 0 && returnValue is IEnumerable)
{
CacheResultItems((IEnumerable)returnValue, cacheResultInfo.ItemInfoArray);
CacheResultItems((IEnumerable)returnValue, cacheResultInfo.ItemInfoArray, vars);
}
return returnValue;
@@ -141,13 +144,16 @@ namespace Spring.Aspects.Cache
/// in which case no caching of the result as a whole will be performed
/// (if the result is collection, individual items could still be cached separately).
/// </param>
/// <param name="vars">
/// Variables for expression evaluation.
/// </param>
/// <param name="cacheHit">
/// Returns <c>true</c> if the return value was found in cache, <c>false</c> otherwise.
/// </param>
/// <returns>
/// Return value for the specified <paramref name="invocation"/>.
/// </returns>
private object GetReturnValue(IMethodInvocation invocation, CacheResultAttribute resultInfo, out bool cacheHit)
private object GetReturnValue(IMethodInvocation invocation, CacheResultAttribute resultInfo, IDictionary vars, out bool cacheHit)
{
if (resultInfo != null)
{
@@ -155,15 +161,13 @@ namespace Spring.Aspects.Cache
bool isLogDebugEnabled = logger.IsDebugEnabled;
#endregion
AssertUtils.ArgumentNotNull(resultInfo.KeyExpression, "Key",
"The cache attribute is missing the key definition.");
object returnValue = null;
IDictionary vars = PrepareVariables(invocation.Method, invocation.Arguments);
AssertUtils.ArgumentNotNull(resultInfo.KeyExpression, "KeyExpression",
"The cache attribute is missing the key definition.");
object resultKey = resultInfo.KeyExpression.GetValue(null, vars);
ICache cache = GetCache(resultInfo.CacheName);
returnValue = cache.Get(resultKey);
cacheHit = (returnValue != null);
if (!cacheHit)
@@ -213,12 +217,15 @@ namespace Spring.Aspects.Cache
/// <param name="itemInfoArray">
/// Attributes specifying where and how to cache each item from the collection.
/// </param>
private void CacheResultItems(IEnumerable items, CacheResultItemsAttribute[] itemInfoArray)
/// <param name="vars">
/// Variables for expression evaluation.
/// </param>
private void CacheResultItems(IEnumerable items, CacheResultItemsAttribute[] itemInfoArray, IDictionary vars)
{
foreach (CacheResultItemsAttribute itemInfo in itemInfoArray)
{
AssertUtils.ArgumentNotNull(itemInfo.KeyExpression, "KeyExpression",
"The cache attribute is missing the key definition.");
AssertUtils.ArgumentNotNull(itemInfo.KeyExpression, "Key",
"The cache attribute is missing the key definition.");
ICache cache = GetCache(itemInfo.CacheName);
@@ -227,9 +234,9 @@ namespace Spring.Aspects.Cache
#endregion
foreach (object item in items)
{
if (EvalCondition(itemInfo.Condition, itemInfo.ConditionExpression, item, null))
if (EvalCondition(itemInfo.Condition, itemInfo.ConditionExpression, item, vars))
{
object itemKey = itemInfo.KeyExpression.GetValue(item);
object itemKey = itemInfo.KeyExpression.GetValue(item, vars);
#region Instrumentation
if (isDebugEnabled)
{

View File

@@ -72,6 +72,23 @@ namespace Spring.Aspects.Cache
mocks.VerifyAll();
}
[Test]
public void TestSimpleWithMethodInfoParameterCaching()
{
MethodInfo method = typeof(SimpleWithMethodInfoCacheParameterTarget).GetMethod("Save");
object[] args = new object[] { new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian") };
ExpectCacheInstanceRetrieval("cache", cache);
mocks.ReplayAll();
// parameter value should be added to cache
advice.AfterReturning(null, method, args, null);
Assert.AreEqual(1, cache.Count);
Assert.AreEqual(args[0], cache.Get("Save-Nikola Tesla"));
mocks.VerifyAll();
}
[Test]
public void TestMultipleParameterCaching()
{
@@ -126,6 +143,13 @@ namespace Spring.Aspects.Cache
}
}
public sealed class SimpleWithMethodInfoCacheParameterTarget : ICacheParameterTarget
{
public void Save([CacheParameter("cache", "#Save.Name + '-' + Name")] Inventor inventor)
{
}
}
public sealed class MultipleCacheParameterTarget : ICacheParameterTarget
{
public void Save([CacheParameter("cache", "Name")][CacheParameter("cache", "Nationality")] Inventor inventor)

View File

@@ -195,6 +195,7 @@ namespace Spring.Aspects.Cache
object expectedReturnValue = new object[] { "one", "two", "three" };
ExpectAttributeRetrieval(method);
ExpectCacheKeyGeneration(method, 5, expectedReturnValue);
ExpectCallToProceed(new object[] { "one", "two", "three" });
ExpectCacheInstanceRetrieval("items", itemCache);
@@ -228,6 +229,7 @@ namespace Spring.Aspects.Cache
object expectedReturnValue = new object[] { "one", "two", "three" };
ExpectAttributeRetrieval(method);
ExpectCacheKeyGeneration(method, 5, expectedReturnValue);
ExpectCallToProceed(new object[] { "one", "two", "three" });
ExpectCacheInstanceRetrieval( "items", itemCache );
ExpectCacheInstanceRetrieval( "items", itemCache );
@@ -264,6 +266,7 @@ namespace Spring.Aspects.Cache
object expectedReturnValue = new object[] { "one", "two", "three" };
ExpectAttributeRetrieval(method);
ExpectCacheKeyGeneration(method, 5, expectedReturnValue);
ExpectCallToProceed(new object[] { "one", "two", "three" });
ExpectCacheInstanceRetrieval( "items", itemCache );
@@ -370,6 +373,49 @@ namespace Spring.Aspects.Cache
mockContext.Verify();
}
[Test]
public void CacheResultWithMethodInfo()
{
MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultWithMethodInfo).Method;
object expectedReturnValue = new object[] { "one", "two", "three" };
ExpectAttributeRetrieval(method);
ExpectCacheKeyGeneration(method, 5, expectedReturnValue);
ExpectCacheInstanceRetrieval("results", resultCache);
ExpectCallToProceed(new object[] { "one", "two", "three" });
// return value should be added to cache
object returnValue = advice.Invoke((IMethodInvocation)mockInvocation.Object);
Assert.AreEqual(expectedReturnValue, returnValue);
Assert.AreEqual(1, resultCache.Count);
Assert.AreEqual(returnValue, resultCache.Get("CacheResultWithMethodInfo-5"));
mockInvocation.Verify();
mockContext.Verify();
}
[Test]
public void CacheResultItemsWithMethodInfo()
{
MethodInfo method = new EnumerableResultMethod(cacheResultTarget.CacheResultItemsWithMethodInfo).Method;
object expectedReturnValue = new object[] { "one", "two", "three" };
ExpectAttributeRetrieval(method);
ExpectCacheKeyGeneration(method, 5, expectedReturnValue);
ExpectCallToProceed(new object[] { "one", "two", "three" });
ExpectCacheInstanceRetrieval("items", itemCache);
// return value should be added to result cache and each item to item cache
object returnValue = advice.Invoke((IMethodInvocation)mockInvocation.Object);
Assert.AreEqual(expectedReturnValue, returnValue);
Assert.AreEqual(0, resultCache.Count);
Assert.AreEqual(3, itemCache.Count);
Assert.AreEqual("two", itemCache.Get("CacheResultItemsWithMethodInfo-two"));
mockInvocation.Verify();
mockContext.Verify();
}
#region Helper methods
@@ -499,6 +545,18 @@ namespace Spring.Aspects.Cache
return elements;
}
[CacheResult("results", "#CacheResultWithMethodInfo.Name + '-' + #key")]
public IEnumerable CacheResultWithMethodInfo(int key, params object[] elements)
{
return elements;
}
[CacheResultItems("items", "#CacheResultItemsWithMethodInfo.Name + '-' + #this")]
public IEnumerable CacheResultItemsWithMethodInfo(int key, params object[] elements)
{
return elements;
}
[CacheResultItems( "items", "#this", Condition = "#this.StartsWith('t')" )]
public IEnumerable CacheResultItemsWithCondition( int key, params object[] elements )
{