Use 'invocation.Method' as variable for cache attributes key expression resolution [SPRNET-959]
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user