CachedAopProxyFactory doesn't take into account the ProxyTargetAttributes property for cache key generation [SPRNET-1371]
This commit is contained in:
@@ -254,7 +254,6 @@ namespace Spring.Aop.Framework.AutoProxy
|
||||
{
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
proxyFactory.ProxyTargetAttributes = this.ProxyTargetAttributes;
|
||||
proxyFactory.ProxyTargetAttributes = this.ProxyDeclaredMembersOnly;
|
||||
proxyFactory.TargetSource = new InheritanceBasedAopTargetSource(objectType);
|
||||
if (!ProxyInterfaces)
|
||||
{
|
||||
|
||||
@@ -1,205 +1,213 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
|
||||
using Common.Logging;
|
||||
using Spring.Proxy;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Aop.Framework.DynamicProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of the <see cref="Spring.Aop.Framework.IAopProxyFactory"/>
|
||||
/// interface that caches the AOP proxy <see cref="System.Type"/> instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// Caches against a key based on :
|
||||
/// - the base type
|
||||
/// - the target type
|
||||
/// - the interfaces to proxy
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <author>Bruno Baia</author>
|
||||
/// <author>Erich Eichinger</author>
|
||||
/// <seealso cref="Spring.Aop.Framework.DynamicProxy.DefaultAopProxyFactory"/>
|
||||
/// <seealso cref="Spring.Aop.Framework.IAopProxyFactory"/>
|
||||
[Serializable]
|
||||
public class CachedAopProxyFactory : DefaultAopProxyFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The shared <see cref="Common.Logging.ILog"/> instance for this class.
|
||||
/// </summary>
|
||||
private static readonly ILog logger = LogManager.GetLogger(typeof(CachedAopProxyFactory));
|
||||
|
||||
private static readonly Hashtable typeCache = new Hashtable();
|
||||
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
|
||||
using Common.Logging;
|
||||
using Spring.Proxy;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Aop.Framework.DynamicProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of the <see cref="Spring.Aop.Framework.IAopProxyFactory"/>
|
||||
/// interface that caches the AOP proxy <see cref="System.Type"/> instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// Caches against a key based on :
|
||||
/// - the base type
|
||||
/// - the target type
|
||||
/// - the interfaces to proxy
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <author>Bruno Baia</author>
|
||||
/// <author>Erich Eichinger</author>
|
||||
/// <seealso cref="Spring.Aop.Framework.DynamicProxy.DefaultAopProxyFactory"/>
|
||||
/// <seealso cref="Spring.Aop.Framework.IAopProxyFactory"/>
|
||||
[Serializable]
|
||||
public class CachedAopProxyFactory : DefaultAopProxyFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The shared <see cref="Common.Logging.ILog"/> instance for this class.
|
||||
/// </summary>
|
||||
private static readonly ILog logger = LogManager.GetLogger(typeof(CachedAopProxyFactory));
|
||||
|
||||
private static readonly Hashtable typeCache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of proxy types in the cache
|
||||
/// </summary>
|
||||
public static int CountCachedTypes
|
||||
/// </summary>
|
||||
public static int CountCachedTypes
|
||||
{
|
||||
get { return typeCache.Count; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the type cache
|
||||
/// </summary>
|
||||
public static void ClearCache()
|
||||
/// </summary>
|
||||
public static void ClearCache()
|
||||
{
|
||||
typeCache.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public CachedAopProxyFactory()
|
||||
/// </summary>
|
||||
public CachedAopProxyFactory()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the proxy type and caches the <see cref="System.Type"/>
|
||||
/// instance against the base type and the interfaces to proxy.
|
||||
/// </summary>
|
||||
/// <param name="typeBuilder">
|
||||
/// The <see cref="Spring.Proxy.IProxyTypeBuilder"/> to use
|
||||
/// </param>
|
||||
/// <returns>The generated or cached proxy class.</returns>
|
||||
protected override Type BuildProxyType(IProxyTypeBuilder typeBuilder)
|
||||
{
|
||||
ProxyTypeCacheKey cacheKey = new ProxyTypeCacheKey(
|
||||
typeBuilder.BaseType, typeBuilder.TargetType, typeBuilder.Interfaces);
|
||||
Type proxyType = null;
|
||||
lock (typeCache)
|
||||
{
|
||||
proxyType = typeCache[cacheKey] as Type;
|
||||
if (proxyType == null)
|
||||
{
|
||||
proxyType = typeBuilder.BuildProxyType();
|
||||
typeCache[cacheKey] = proxyType;
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (logger.IsInfoEnabled)
|
||||
{
|
||||
logger.Info(String.Format(
|
||||
"AOP proxy type found in cache for '{0}'.", cacheKey));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
return proxyType;
|
||||
}
|
||||
|
||||
#region ProxyTypeCacheKey inner class implementation
|
||||
|
||||
/// <summary>
|
||||
/// Uniquely identifies a proxytype in the cache
|
||||
/// </summary>
|
||||
private sealed class ProxyTypeCacheKey
|
||||
{
|
||||
private sealed class HashCodeComparer : IComparer
|
||||
{
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
return x.GetHashCode().CompareTo(y.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private static IComparer interfaceComparer = new HashCodeComparer();
|
||||
|
||||
private Type baseType;
|
||||
private Type targetType;
|
||||
private Type[] interfaceTypes;
|
||||
|
||||
public ProxyTypeCacheKey(Type baseType, Type targetType, Type[] interfaceTypes)
|
||||
{
|
||||
this.baseType = baseType;
|
||||
this.targetType = targetType;
|
||||
Array.Sort(interfaceTypes, interfaceComparer); // sort by GetHashcode()? to have a defined order
|
||||
this.interfaceTypes = interfaceTypes;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ProxyTypeCacheKey proxyTypeCacheKey = obj as ProxyTypeCacheKey;
|
||||
if (proxyTypeCacheKey == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Equals(targetType, proxyTypeCacheKey.targetType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Equals(baseType, proxyTypeCacheKey.baseType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < interfaceTypes.Length; i++)
|
||||
{
|
||||
if (!Equals(interfaceTypes[i], proxyTypeCacheKey.interfaceTypes[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int result = baseType.GetHashCode();
|
||||
result = 29*result + targetType.GetHashCode();
|
||||
for (int i = 0; i < interfaceTypes.Length; i++)
|
||||
{
|
||||
result = 29 * result + interfaceTypes[i].GetHashCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("baseType=" + baseType + "; ");
|
||||
buffer.Append("targetType=" + targetType + "; ");
|
||||
buffer.Append("interfaceTypes=[");
|
||||
foreach (Type intf in interfaceTypes)
|
||||
{
|
||||
buffer.Append(intf + ";");
|
||||
}
|
||||
buffer.Append("]; ");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// Generates the proxy type and caches the <see cref="System.Type"/>
|
||||
/// instance against the base type and the interfaces to proxy.
|
||||
/// </summary>
|
||||
/// <param name="typeBuilder">
|
||||
/// The <see cref="Spring.Proxy.IProxyTypeBuilder"/> to use
|
||||
/// </param>
|
||||
/// <returns>The generated or cached proxy class.</returns>
|
||||
protected override Type BuildProxyType(IProxyTypeBuilder typeBuilder)
|
||||
{
|
||||
ProxyTypeCacheKey cacheKey = new ProxyTypeCacheKey(
|
||||
typeBuilder.BaseType, typeBuilder.TargetType, typeBuilder.Interfaces, typeBuilder.ProxyTargetAttributes);
|
||||
Type proxyType = null;
|
||||
lock (typeCache)
|
||||
{
|
||||
proxyType = typeCache[cacheKey] as Type;
|
||||
if (proxyType == null)
|
||||
{
|
||||
proxyType = typeBuilder.BuildProxyType();
|
||||
typeCache[cacheKey] = proxyType;
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (logger.IsInfoEnabled)
|
||||
{
|
||||
logger.Info(String.Format(
|
||||
"AOP proxy type found in cache for '{0}'.", cacheKey));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
return proxyType;
|
||||
}
|
||||
|
||||
#region ProxyTypeCacheKey inner class implementation
|
||||
|
||||
/// <summary>
|
||||
/// Uniquely identifies a proxytype in the cache
|
||||
/// </summary>
|
||||
private sealed class ProxyTypeCacheKey
|
||||
{
|
||||
private sealed class HashCodeComparer : IComparer
|
||||
{
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
return x.GetHashCode().CompareTo(y.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private static IComparer interfaceComparer = new HashCodeComparer();
|
||||
|
||||
private Type baseType;
|
||||
private Type targetType;
|
||||
private Type[] interfaceTypes;
|
||||
private bool proxyTargetAttributes;
|
||||
|
||||
public ProxyTypeCacheKey(Type baseType, Type targetType, Type[] interfaceTypes, bool proxyTargetAttributes)
|
||||
{
|
||||
this.baseType = baseType;
|
||||
this.targetType = targetType;
|
||||
Array.Sort(interfaceTypes, interfaceComparer); // sort by GetHashcode()? to have a defined order
|
||||
this.interfaceTypes = interfaceTypes;
|
||||
this.proxyTargetAttributes = proxyTargetAttributes;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ProxyTypeCacheKey proxyTypeCacheKey = obj as ProxyTypeCacheKey;
|
||||
if (proxyTypeCacheKey == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Equals(targetType, proxyTypeCacheKey.targetType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Equals(baseType, proxyTypeCacheKey.baseType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < interfaceTypes.Length; i++)
|
||||
{
|
||||
if (!Equals(interfaceTypes[i], proxyTypeCacheKey.interfaceTypes[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (proxyTargetAttributes != proxyTypeCacheKey.proxyTargetAttributes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int result = baseType.GetHashCode();
|
||||
result = 29*result + targetType.GetHashCode();
|
||||
for (int i = 0; i < interfaceTypes.Length; i++)
|
||||
{
|
||||
result = 29 * result + interfaceTypes[i].GetHashCode();
|
||||
}
|
||||
result = 29 * result + proxyTargetAttributes.GetHashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("baseType=" + baseType + "; ");
|
||||
buffer.Append("targetType=" + targetType + "; ");
|
||||
buffer.Append("interfaceTypes=[");
|
||||
foreach (Type intf in interfaceTypes)
|
||||
{
|
||||
buffer.Append(intf + ";");
|
||||
}
|
||||
buffer.Append("]; ");
|
||||
buffer.Append("proxyTargetAttributes=" + proxyTargetAttributes + "; ");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,20 @@ namespace Spring.Aop.Framework.DynamicProxy
|
||||
AssertAopProxyTypeCacheCount(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotCacheWithDifferentProxyTargetAttributes()
|
||||
{
|
||||
ProxyFactory advisedSupport = new ProxyFactory(new GoodCommand());
|
||||
advisedSupport.ProxyTargetAttributes = true;
|
||||
CreateAopProxy(advisedSupport);
|
||||
|
||||
advisedSupport = new ProxyFactory(new GoodCommand());
|
||||
advisedSupport.ProxyTargetAttributes = false;
|
||||
CreateAopProxy(advisedSupport);
|
||||
|
||||
AssertAopProxyTypeCacheCount(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotCacheWithDifferentInterfaces()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user