partial fix for SPRNET-1221 (avoid duplicate advice invocations for nested proxies)
This commit is contained in:
@@ -42,12 +42,24 @@ namespace Spring.Aop.Framework
|
||||
/// <author>Aleksandar Seovic (.NET)</author>
|
||||
public sealed class AopUtils
|
||||
{
|
||||
|
||||
// This is a leaky abstraction as we have hardcoded known IAopProxyFactory implementations.
|
||||
private const string COMPOSITION_PROXY_TYPE_NAME = "CompositionAopProxy";
|
||||
|
||||
private const string DECORATOR_PROXY_TYPE_NAME = "DecoratorAopProxy";
|
||||
|
||||
/// <summary>
|
||||
/// Is the supplied <paramref name="objectType"/> an AOP proxy?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Return whether the given type is either a composition-based or a decorator-based proxy type.
|
||||
/// </remarks>
|
||||
/// <param name="objectType">The type to be checked.</param>
|
||||
/// <returns><see langword="true"/> if the supplied <paramref name="objectType"/> is an AOP proxy type.</returns>
|
||||
public static bool IsAopProxyType(Type objectType)
|
||||
{
|
||||
return IsCompositionAopProxyType(objectType) || IsDecoratorAopProxyType(objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the supplied <paramref name="instance"/> an AOP proxy?
|
||||
/// </summary>
|
||||
@@ -75,7 +87,20 @@ namespace Spring.Aop.Framework
|
||||
/// </returns>
|
||||
public static bool IsCompositionAopProxy(Object instance)
|
||||
{
|
||||
return ((instance != null) && instance.GetType().FullName.StartsWith(COMPOSITION_PROXY_TYPE_NAME));
|
||||
return ((instance != null) && IsCompositionAopProxyType(instance.GetType()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the supplied <paramref name="objectType"/> a composition based AOP proxy type?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Return whether the given type is a composition-based proxy type.
|
||||
/// </remarks>
|
||||
/// <param name="objectType">The type to be checked.</param>
|
||||
/// <returns><see langword="true"/> if the supplied <paramref name="objectType"/> is a composition based AOP proxy type.</returns>
|
||||
public static bool IsCompositionAopProxyType(Type objectType)
|
||||
{
|
||||
return ((objectType != null) && objectType.FullName.StartsWith(COMPOSITION_PROXY_TYPE_NAME));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -88,7 +113,20 @@ namespace Spring.Aop.Framework
|
||||
/// </returns>
|
||||
public static bool IsDecoratorAopProxy(Object instance)
|
||||
{
|
||||
return ((instance != null) && instance.GetType().FullName.StartsWith(DECORATOR_PROXY_TYPE_NAME));
|
||||
return ((instance != null) && IsDecoratorAopProxyType(instance.GetType()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the supplied <paramref name="objectType"/> a composition based AOP proxy type?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Return whether the given type is a composition-based proxy type.
|
||||
/// </remarks>
|
||||
/// <param name="objectType">The type to be checked.</param>
|
||||
/// <returns><see langword="true"/> if the supplied <paramref name="objectType"/> is a composition based AOP proxy type.</returns>
|
||||
public static bool IsDecoratorAopProxyType(Type objectType)
|
||||
{
|
||||
return ((objectType != null) && objectType.FullName.StartsWith(DECORATOR_PROXY_TYPE_NAME));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#region License
|
||||
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2007 the original author or authors.
|
||||
* Copyright <20> 2002-2009 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.
|
||||
@@ -14,104 +14,128 @@
|
||||
* 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
|
||||
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using Spring.Proxy;
|
||||
using Spring.Aop.Support;
|
||||
using Spring.Proxy;
|
||||
using Spring.Aop.Target;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Aop.Framework.DynamicProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of the
|
||||
/// <see cref="Spring.Aop.Framework.IAopProxyFactory"/> interface,
|
||||
/// either creating a decorator-based dynamic proxy or
|
||||
/// a composition-based dynamic proxy.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// Creates a decorator-base proxy if one the following is true :
|
||||
/// - the "ProxyTargetType" property is set
|
||||
/// - no interfaces have been specified
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// In general, specify "ProxyTargetType" to enforce a decorator-based proxy,
|
||||
/// or specify one or more interfaces to use a composition-based proxy.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <author>Rod Johnson</author>
|
||||
/// <author>Aleksandar Seovic (.NET)</author>
|
||||
/// <author>Bruno Baia (.NET)</author>
|
||||
/// <seealso cref="Spring.Aop.Framework.IAopProxyFactory"/>
|
||||
[Serializable]
|
||||
public class DefaultAopProxyFactory : IAopProxyFactory
|
||||
{
|
||||
using Spring.Util;
|
||||
|
||||
namespace Spring.Aop.Framework.DynamicProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of the
|
||||
/// <see cref="Spring.Aop.Framework.IAopProxyFactory"/> interface,
|
||||
/// either creating a decorator-based dynamic proxy or
|
||||
/// a composition-based dynamic proxy.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// Creates a decorator-base proxy if one the following is true :
|
||||
/// - the "ProxyTargetType" property is set
|
||||
/// - no interfaces have been specified
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// In general, specify "ProxyTargetType" to enforce a decorator-based proxy,
|
||||
/// or specify one or more interfaces to use a composition-based proxy.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <author>Rod Johnson</author>
|
||||
/// <author>Aleksandar Seovic (.NET)</author>
|
||||
/// <author>Bruno Baia (.NET)</author>
|
||||
/// <author>Erich Eichinger (.NET)</author>
|
||||
/// <seealso cref="Spring.Aop.Framework.IAopProxyFactory"/>
|
||||
[Serializable]
|
||||
public class DefaultAopProxyFactory : IAopProxyFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Force transient assemblies to be resolvable by <see cref="Assembly.Load(string)"/>.
|
||||
/// </summary>
|
||||
static DefaultAopProxyFactory()
|
||||
/// </summary>
|
||||
static DefaultAopProxyFactory()
|
||||
{
|
||||
SystemUtils.RegisterLoadedAssemblyResolver();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="Spring.Aop.Framework.IAopProxy"/> for the
|
||||
/// supplied <paramref name="advisedSupport"/> configuration.
|
||||
/// </summary>
|
||||
/// <param name="advisedSupport">The AOP configuration.</param>
|
||||
/// <returns>An <see cref="Spring.Aop.Framework.IAopProxy"/>.</returns>
|
||||
/// <exception cref="AopConfigException">
|
||||
/// If the supplied <paramref name="advisedSupport"/> configuration is
|
||||
/// invalid.
|
||||
/// </exception>
|
||||
/// <seealso cref="Spring.Aop.Framework.IAopProxyFactory.CreateAopProxy"/>
|
||||
public virtual IAopProxy CreateAopProxy(AdvisedSupport advisedSupport)
|
||||
{
|
||||
if (advisedSupport == null)
|
||||
{
|
||||
throw new AopConfigException("Cannot create IAopProxy with null ProxyConfig");
|
||||
}
|
||||
if (advisedSupport.Advisors.Length == 0 && advisedSupport.TargetSource == EmptyTargetSource.Empty)
|
||||
{
|
||||
throw new AopConfigException("Cannot create IAopProxy with no advisors and no target source");
|
||||
}
|
||||
if (advisedSupport.ProxyType == null)
|
||||
{
|
||||
IProxyTypeBuilder typeBuilder;
|
||||
if ((advisedSupport.ProxyTargetType) ||
|
||||
(advisedSupport.Interfaces.Length == 0))
|
||||
{
|
||||
typeBuilder = new DecoratorAopProxyTypeBuilder(advisedSupport);
|
||||
}
|
||||
else
|
||||
{
|
||||
typeBuilder = new CompositionAopProxyTypeBuilder(advisedSupport);
|
||||
}
|
||||
advisedSupport.ProxyType = BuildProxyType(typeBuilder);
|
||||
advisedSupport.ProxyConstructor = advisedSupport.ProxyType.GetConstructor(new Type[] { typeof(IAdvised) });
|
||||
}
|
||||
|
||||
return (IAopProxy)advisedSupport.ProxyConstructor.Invoke(new object[] { advisedSupport });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the proxy type.
|
||||
/// </summary>
|
||||
/// <param name="typeBuilder">
|
||||
/// The <see cref="Spring.Proxy.IProxyTypeBuilder"/> to use
|
||||
/// </param>
|
||||
/// <returns>The generated proxy class.</returns>
|
||||
protected virtual Type BuildProxyType(IProxyTypeBuilder typeBuilder)
|
||||
{
|
||||
return typeBuilder.BuildProxyType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="Spring.Aop.Framework.IAopProxy"/> for the
|
||||
/// supplied <paramref name="advisedSupport"/> configuration.
|
||||
/// </summary>
|
||||
/// <param name="advisedSupport">The AOP configuration.</param>
|
||||
/// <returns>An <see cref="Spring.Aop.Framework.IAopProxy"/>.</returns>
|
||||
/// <exception cref="AopConfigException">
|
||||
/// If the supplied <paramref name="advisedSupport"/> configuration is
|
||||
/// invalid.
|
||||
/// </exception>
|
||||
/// <seealso cref="Spring.Aop.Framework.IAopProxyFactory.CreateAopProxy"/>
|
||||
public virtual IAopProxy CreateAopProxy(AdvisedSupport advisedSupport)
|
||||
{
|
||||
if (advisedSupport == null)
|
||||
{
|
||||
throw new AopConfigException("Cannot create IAopProxy with null ProxyConfig");
|
||||
}
|
||||
if (advisedSupport.Advisors.Length == 0 && advisedSupport.TargetSource == EmptyTargetSource.Empty)
|
||||
{
|
||||
throw new AopConfigException("Cannot create IAopProxy with no advisors and no target source");
|
||||
}
|
||||
if (advisedSupport.ProxyType == null)
|
||||
{
|
||||
IProxyTypeBuilder typeBuilder;
|
||||
if ((advisedSupport.ProxyTargetType) ||
|
||||
(advisedSupport.Interfaces.Length == 0))
|
||||
{
|
||||
typeBuilder = new DecoratorAopProxyTypeBuilder(advisedSupport);
|
||||
}
|
||||
else
|
||||
{
|
||||
typeBuilder = new CompositionAopProxyTypeBuilder(advisedSupport);
|
||||
}
|
||||
advisedSupport.ProxyType = BuildProxyType(typeBuilder);
|
||||
advisedSupport.ProxyConstructor = advisedSupport.ProxyType.GetConstructor(new Type[] { typeof(IAdvised) });
|
||||
}
|
||||
|
||||
if (advisedSupport.TargetSource is SingletonTargetSource
|
||||
&& AopUtils.IsAopProxyType(advisedSupport.TargetSource.TargetType))
|
||||
{
|
||||
IAdvised innerProxy = (IAdvised)advisedSupport.TargetSource.GetTarget();
|
||||
// eliminate duplicate advisors
|
||||
ArrayList thisAdvisors = new ArrayList(advisedSupport.Advisors);
|
||||
foreach (IAdvisor innerAdvisor in innerProxy.Advisors)
|
||||
{
|
||||
foreach (IAdvisor thisAdvisor in thisAdvisors)
|
||||
{
|
||||
if (ReferenceEquals(thisAdvisor, innerAdvisor)
|
||||
|| (thisAdvisor.GetType() == typeof(DefaultPointcutAdvisor)
|
||||
&& ((DefaultPointcutAdvisor)thisAdvisor).Equals(innerAdvisor)
|
||||
)
|
||||
)
|
||||
{
|
||||
advisedSupport.RemoveAdvisor(thisAdvisor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// elimination of duplicate introductions is not necessary
|
||||
// since they do not propagate to nested proxy anyway
|
||||
}
|
||||
|
||||
return (IAopProxy)advisedSupport.ProxyConstructor.Invoke(new object[] { advisedSupport });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the proxy type.
|
||||
/// </summary>
|
||||
/// <param name="typeBuilder">
|
||||
/// The <see cref="Spring.Proxy.IProxyTypeBuilder"/> to use
|
||||
/// </param>
|
||||
/// <returns>The generated proxy class.</returns>
|
||||
protected virtual Type BuildProxyType(IProxyTypeBuilder typeBuilder)
|
||||
{
|
||||
return typeBuilder.BuildProxyType();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ namespace Spring.Aop.Support
|
||||
{
|
||||
private IAdvice advice;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Return the advice part of this advisor.
|
||||
/// </summary>
|
||||
@@ -47,7 +46,24 @@ namespace Spring.Aop.Support
|
||||
set { this.advice = value; }
|
||||
}
|
||||
|
||||
|
||||
///<summary>
|
||||
/// 2 <see cref="AbstractGenericPointcutAdvisor"/>s are considered equals, if
|
||||
/// a) their pointcuts are equal
|
||||
/// b) their advices are equal
|
||||
///</summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return base.Equals(obj as AbstractGenericPointcutAdvisor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a unique hashcode based on advice + pointcut
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String"/> that represents the current
|
||||
/// <see cref="System.Object"/>.
|
||||
|
||||
@@ -126,8 +126,18 @@ namespace Spring.Aop.Support
|
||||
if (!(o is AbstractPointcutAdvisor))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, o))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractPointcutAdvisor otherAdvisor = (AbstractPointcutAdvisor)o;
|
||||
if (this.Order != otherAdvisor.Order)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
IPointcutAdvisor otherAdvisor = (IPointcutAdvisor)o;
|
||||
if (otherAdvisor.Advice == null && otherAdvisor.Pointcut == null)
|
||||
{
|
||||
return (this.Advice == null && this.Pointcut == null);
|
||||
@@ -157,7 +167,8 @@ namespace Spring.Aop.Support
|
||||
{
|
||||
return 0 // (SPRNET-847) base.GetHashCode()
|
||||
+ 13 * (Pointcut == null ? 0 : Pointcut.GetHashCode())
|
||||
+ 27 * (Advice == null ? 0 : Advice.GetHashCode());
|
||||
+ 27 * (Advice == null ? 0 : Advice.GetHashCode())
|
||||
+ 31 * Order.GetHashCode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace Spring.Aop.Support
|
||||
[Serializable]
|
||||
public class DefaultIntroductionAdvisor : IIntroductionAdvisor, ITypeFilter
|
||||
{
|
||||
private IAdvice _introduction;
|
||||
private ISet _interfaces = new HybridSet();
|
||||
private readonly IAdvice _introduction;
|
||||
private readonly ISet _interfaces = new HybridSet();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the
|
||||
@@ -236,5 +236,45 @@ namespace Spring.Aop.Support
|
||||
throw new ArgumentException("Type [" + intf.FullName + "] is not an interface; cannot be used in an introduction.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2 IntroductionAdvisors are considered equal if
|
||||
/// a) they are of the same type
|
||||
/// b) their introduction advices are equal
|
||||
/// c) they introduce the same interfaces
|
||||
/// </summary>
|
||||
public bool Equals(DefaultIntroductionAdvisor other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (other.GetType() != this.GetType())
|
||||
return false;
|
||||
return Equals(other._introduction, _introduction) && Equals(other._interfaces, _interfaces);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2 IntroductionAdvisors are considered equal if
|
||||
/// a) they are of the same type
|
||||
/// b) their introduction advices are equal
|
||||
/// c) they introduce the same interfaces
|
||||
/// </summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as DefaultIntroductionAdvisor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2 IntroductionAdvisors are considered equal if
|
||||
/// a) they are of the same type
|
||||
/// b) their introduction advices are equal
|
||||
/// c) they introduce the same interfaces
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((_introduction != null ? _introduction.GetHashCode() : 0)*397) ^ (_interfaces != null ? _interfaces.GetHashCode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,6 @@ namespace Spring.Aop.Support
|
||||
[Serializable]
|
||||
public class DefaultPointcutAdvisor : AbstractGenericPointcutAdvisor
|
||||
{
|
||||
|
||||
private IPointcut pointcut = TruePointcut.True;
|
||||
|
||||
/// <summary>
|
||||
@@ -90,12 +89,28 @@ namespace Spring.Aop.Support
|
||||
{
|
||||
get { return pointcut; }
|
||||
set { pointcut = value;}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
}
|
||||
|
||||
|
||||
///<summary>
|
||||
/// 2 <see cref="DefaultPointcutAdvisor"/>s are considered equal, if
|
||||
/// a) their pointcuts are equal
|
||||
/// b) their advices are equal
|
||||
///</summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return base.Equals(obj as DefaultPointcutAdvisor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a unique hashcode based on advice + pointcut
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String"/> that represents the current
|
||||
/// <see cref="System.Object"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -66,10 +66,10 @@ namespace Spring.Aop.Framework.AutoProxy
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProxyWithDoubleProxying()
|
||||
public void ProxyWithDoubleProxyingInvokesInterceptorsOnceOnly()
|
||||
{
|
||||
ITestObject testObject = (ITestObject)ctx.GetObject("doubleProxy");
|
||||
ProxyAssertions(testObject, 2);
|
||||
ProxyAssertions(testObject, 1);
|
||||
Assert.AreEqual("doubleProxy", testObject.Name);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Spring.Aop.Framework.AutoProxy
|
||||
int age = 5;
|
||||
testObject.Age = age;
|
||||
Assert.AreEqual(age, testObject.Age);
|
||||
Assert.AreEqual(2 * nopInterceptorCount, nop.Count);
|
||||
Assert.AreEqual(2*nopInterceptorCount, nop.Count);
|
||||
}
|
||||
|
||||
private void DecoratorProxyAssertions(ITestObject testObject)
|
||||
|
||||
@@ -211,27 +211,27 @@ namespace Spring.Aop.Framework
|
||||
pf.AddAdvice(nopInterceptor);
|
||||
pf.AddAdvisor(new DefaultPointcutAdvisor(countingBeforeAdvice));
|
||||
object proxy = pf.GetProxy();
|
||||
ITestObject to = (ITestObject) proxy;
|
||||
ITestObject to = (ITestObject)proxy;
|
||||
Assert.AreEqual("Adam", to.Name);
|
||||
Assert.AreEqual(1, countingBeforeAdvice.GetCalls());
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof (AopConfigException))]
|
||||
[ExpectedException(typeof(AopConfigException))]
|
||||
public void InstantiateWithNullTarget()
|
||||
{
|
||||
new ProxyFactory((object) null);
|
||||
new ProxyFactory((object)null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof (ArgumentNullException))]
|
||||
[ExpectedException(typeof(ArgumentNullException))]
|
||||
public void AddNullInterface()
|
||||
{
|
||||
new ProxyFactory().AddInterface(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof (AopConfigException))]
|
||||
[ExpectedException(typeof(AopConfigException))]
|
||||
public void AddInterfaceWhenConfigurationIsFrozen()
|
||||
{
|
||||
ProxyFactory factory = new ProxyFactory();
|
||||
@@ -246,16 +246,16 @@ namespace Spring.Aop.Framework
|
||||
ProxyFactory pf = new ProxyFactory(target);
|
||||
NopInterceptor nop = new NopInterceptor();
|
||||
IAdvisor advisor = new DefaultPointcutAdvisor(new CountingBeforeAdvice());
|
||||
IAdvised advised = (IAdvised) pf.GetProxy();
|
||||
IAdvised advised = (IAdvised)pf.GetProxy();
|
||||
// Can use advised and ProxyFactory interchangeably
|
||||
advised.AddAdvice(nop);
|
||||
pf.AddAdvisor(advisor);
|
||||
Assert.AreEqual(- 1, pf.IndexOf((IInterceptor) null));
|
||||
Assert.AreEqual(- 1, pf.IndexOf(new NopInterceptor()));
|
||||
Assert.AreEqual(-1, pf.IndexOf((IInterceptor)null));
|
||||
Assert.AreEqual(-1, pf.IndexOf(new NopInterceptor()));
|
||||
Assert.AreEqual(0, pf.IndexOf(nop));
|
||||
Assert.AreEqual(- 1, advised.IndexOf((IAdvisor) null));
|
||||
Assert.AreEqual(-1, advised.IndexOf((IAdvisor)null));
|
||||
Assert.AreEqual(1, pf.IndexOf(advisor));
|
||||
Assert.AreEqual(- 1, advised.IndexOf(new DefaultPointcutAdvisor(null)));
|
||||
Assert.AreEqual(-1, advised.IndexOf(new DefaultPointcutAdvisor(null)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -268,7 +268,7 @@ namespace Spring.Aop.Framework
|
||||
IAdvisor advisor = new DefaultPointcutAdvisor(cba);
|
||||
pf.AddAdvice(nop);
|
||||
pf.AddAdvisor(advisor);
|
||||
ITestObject proxied = (ITestObject) pf.GetProxy();
|
||||
ITestObject proxied = (ITestObject)pf.GetProxy();
|
||||
proxied.Age = 5;
|
||||
Assert.AreEqual(1, cba.GetCalls());
|
||||
Assert.AreEqual(1, nop.Count);
|
||||
@@ -292,7 +292,7 @@ namespace Spring.Aop.Framework
|
||||
pf.AddAdvisor(advisor);
|
||||
NopInterceptor nop2 = new NopInterceptor(2); // make instance unique (see SPRNET-847)
|
||||
pf.AddAdvice(nop2);
|
||||
ITestObject proxied = (ITestObject) pf.GetProxy();
|
||||
ITestObject proxied = (ITestObject)pf.GetProxy();
|
||||
proxied.Age = 5;
|
||||
Assert.AreEqual(1, cba.GetCalls());
|
||||
Assert.AreEqual(1, nop.Count);
|
||||
@@ -313,7 +313,7 @@ namespace Spring.Aop.Framework
|
||||
// Check out of bounds
|
||||
try
|
||||
{
|
||||
pf.RemoveAdvisor(- 1);
|
||||
pf.RemoveAdvisor(-1);
|
||||
Assert.Fail("Supposed to throw exception");
|
||||
}
|
||||
catch (AopConfigException)
|
||||
@@ -338,14 +338,14 @@ namespace Spring.Aop.Framework
|
||||
[Test]
|
||||
public void TryRemoveNonProxiedInterface()
|
||||
{
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject ());
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject());
|
||||
Assert.IsFalse(factory.RemoveInterface(typeof(IServiceProvider)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveProxiedInterface()
|
||||
{
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject ());
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject());
|
||||
Assert.IsTrue(factory.RemoveInterface(typeof(ITestObject)));
|
||||
}
|
||||
|
||||
@@ -361,10 +361,10 @@ namespace Spring.Aop.Framework
|
||||
IAdvisor advisor2 = new DefaultPointcutAdvisor(cba2);
|
||||
pf.AddAdvisor(advisor1);
|
||||
pf.AddAdvice(nop);
|
||||
ITestObject proxied = (ITestObject) pf.GetProxy();
|
||||
ITestObject proxied = (ITestObject)pf.GetProxy();
|
||||
// Use the type cast feature
|
||||
// Replace etc methods on advised should be same as on ProxyFactory
|
||||
IAdvised advised = (IAdvised) proxied;
|
||||
IAdvised advised = (IAdvised)proxied;
|
||||
proxied.Age = 5;
|
||||
Assert.AreEqual(1, cba1.GetCalls());
|
||||
Assert.AreEqual(0, cba2.GetCalls());
|
||||
@@ -427,9 +427,9 @@ namespace Spring.Aop.Framework
|
||||
ProxyFactory pf = new ProxyFactory(tst);
|
||||
// We've already implicitly added this interface.
|
||||
// This call should be ignored without error
|
||||
pf.AddInterface(typeof (ITimeStamped));
|
||||
pf.AddInterface(typeof(ITimeStamped));
|
||||
// All cool
|
||||
ITimeStamped ts = (ITimeStamped) pf.GetProxy();
|
||||
ITimeStamped ts = (ITimeStamped)pf.GetProxy();
|
||||
}
|
||||
|
||||
internal class TestObjectSubclass : TestObject, IComparable
|
||||
@@ -448,7 +448,7 @@ namespace Spring.Aop.Framework
|
||||
ProxyFactory factory = new ProxyFactory(raw);
|
||||
Assert.AreEqual(8, factory.Interfaces.Length, "Found correct number of interfaces");
|
||||
//System.out.println("Proxied interfaces are " + StringUtils.arrayToDelimitedString(factory.getProxiedInterfaces(), ","));
|
||||
ITestObject tb = (ITestObject) factory.GetProxy();
|
||||
ITestObject tb = (ITestObject)factory.GetProxy();
|
||||
Assert.IsTrue(tb is IOther, "Picked up secondary interface");
|
||||
|
||||
raw.Age = 25;
|
||||
@@ -461,15 +461,15 @@ namespace Spring.Aop.Framework
|
||||
|
||||
//factory.addAdvisor(0, new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)));
|
||||
factory.AddIntroduction(
|
||||
new DefaultIntroductionAdvisor(ti, typeof (ITimeStamped))
|
||||
new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped))
|
||||
);
|
||||
|
||||
Console.WriteLine(StringUtils.ArrayToDelimitedString(factory.Interfaces, "/"));
|
||||
|
||||
ITimeStamped ts = (ITimeStamped) factory.GetProxy();
|
||||
ITimeStamped ts = (ITimeStamped)factory.GetProxy();
|
||||
Assert.IsTrue(ts.TimeStamp == t);
|
||||
// Shouldn't fail;
|
||||
((IOther) ts).Absquatulate();
|
||||
((IOther)ts).Absquatulate();
|
||||
}
|
||||
|
||||
private class AnonymousClassInterceptor : IInterceptor
|
||||
@@ -491,7 +491,7 @@ namespace Spring.Aop.Framework
|
||||
}
|
||||
|
||||
// Check we can still use it
|
||||
IOther other = (IOther) factory.GetProxy();
|
||||
IOther other = (IOther)factory.GetProxy();
|
||||
other.Absquatulate();
|
||||
}
|
||||
|
||||
@@ -502,21 +502,21 @@ namespace Spring.Aop.Framework
|
||||
NopInterceptor diUnused = new NopInterceptor(1); // // make instance unique (see SPRNET-847)
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject());
|
||||
factory.AddAdvice(0, di);
|
||||
ITestObject tb = (ITestObject) factory.GetProxy();
|
||||
ITestObject tb = (ITestObject)factory.GetProxy();
|
||||
Assert.IsTrue(factory.AdviceIncluded(di));
|
||||
Assert.IsTrue(!factory.AdviceIncluded(diUnused));
|
||||
Assert.IsTrue(factory.CountAdviceOfType(typeof (NopInterceptor)) == 1);
|
||||
Assert.IsTrue(factory.CountAdviceOfType(typeof(NopInterceptor)) == 1);
|
||||
|
||||
factory.AddAdvice(0, diUnused);
|
||||
Assert.IsTrue(factory.AdviceIncluded(diUnused));
|
||||
Assert.IsTrue(factory.CountAdviceOfType(typeof (NopInterceptor)) == 2);
|
||||
Assert.IsTrue(factory.CountAdviceOfType(typeof(NopInterceptor)) == 2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddAdvisedSupportListener()
|
||||
{
|
||||
IDynamicMock mock = new DynamicMock(typeof(IAdvisedSupportListener));
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener) mock.Object;
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener)mock.Object;
|
||||
|
||||
mock.Expect("Activated");
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject());
|
||||
@@ -529,7 +529,7 @@ namespace Spring.Aop.Framework
|
||||
public void AdvisedSupportListenerMethodsAreCalledAppropriately()
|
||||
{
|
||||
IDynamicMock mock = new DynamicMock(typeof(IAdvisedSupportListener));
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener) mock.Object;
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener)mock.Object;
|
||||
|
||||
mock.Expect("Activated");
|
||||
mock.Expect("AdviceChanged");
|
||||
@@ -552,7 +552,7 @@ namespace Spring.Aop.Framework
|
||||
public void AdvisedSupportListenerMethodsAre_NOT_CalledIfProxyHasNotBeenCreated()
|
||||
{
|
||||
IDynamicMock mock = new DynamicMock(typeof(IAdvisedSupportListener));
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener) mock.Object;
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener)mock.Object;
|
||||
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject());
|
||||
factory.AddListener(listener);
|
||||
@@ -583,7 +583,7 @@ namespace Spring.Aop.Framework
|
||||
public void RemoveAdvisedSupportListener()
|
||||
{
|
||||
IDynamicMock mock = new DynamicMock(typeof(IAdvisedSupportListener));
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener) mock.Object;
|
||||
IAdvisedSupportListener listener = (IAdvisedSupportListener)mock.Object;
|
||||
|
||||
ProxyFactory factory = new ProxyFactory(new TestObject());
|
||||
factory.AddListener(listener);
|
||||
@@ -603,5 +603,73 @@ namespace Spring.Aop.Framework
|
||||
factory.IsFrozen = true;
|
||||
factory.RemoveAdvisor(null);
|
||||
}
|
||||
|
||||
public interface IMultiProxyingTestInterface
|
||||
{
|
||||
string TestMethod(string arg);
|
||||
}
|
||||
|
||||
public interface IMultiProxyingTestInterface2 : IMultiProxyingTestInterface { }
|
||||
|
||||
public class MultiProxyingTestClass : IMultiProxyingTestInterface2
|
||||
{
|
||||
public int InvocationCounter;
|
||||
|
||||
public string TestMethod(string arg)
|
||||
{
|
||||
InvocationCounter++;
|
||||
return arg + "|" + arg;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICountingIntroduction
|
||||
{
|
||||
void Inc();
|
||||
}
|
||||
|
||||
public class TestCountingIntroduction : ICountingIntroduction, IAdvice
|
||||
{
|
||||
public int Counter;
|
||||
|
||||
public void Inc()
|
||||
{
|
||||
Counter++;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NestedProxiesDontInvokeSameAdviceOrIntroductionTwice()
|
||||
{
|
||||
MultiProxyingTestClass testObj = new MultiProxyingTestClass();
|
||||
ProxyFactory pf1 = new ProxyFactory();
|
||||
pf1.Target = testObj;
|
||||
|
||||
NopInterceptor di = new NopInterceptor();
|
||||
NopInterceptor diUnused = new NopInterceptor(1); // // make instance unique (see SPRNET-847)
|
||||
TestCountingIntroduction countingMixin = new TestCountingIntroduction();
|
||||
|
||||
pf1.AddAdvice(diUnused);
|
||||
pf1.AddAdvisor(new DefaultPointcutAdvisor(di));
|
||||
pf1.AddIntroduction(new DefaultIntroductionAdvisor(countingMixin));
|
||||
|
||||
object innerProxy = pf1.GetProxy();
|
||||
ProxyFactory pf2 = new ProxyFactory();
|
||||
pf2.Target = innerProxy;
|
||||
pf2.AddAdvice(diUnused);
|
||||
pf2.AddAdvisor(new DefaultPointcutAdvisor(di));
|
||||
pf2.AddIntroduction(new DefaultIntroductionAdvisor(countingMixin));
|
||||
|
||||
object outerProxy = pf2.GetProxy();
|
||||
|
||||
// any advice instance is invoked once only
|
||||
string result = ((IMultiProxyingTestInterface)outerProxy).TestMethod("arg");
|
||||
Assert.AreEqual(1, testObj.InvocationCounter);
|
||||
Assert.AreEqual("arg|arg", result);
|
||||
Assert.AreEqual(1, di.Count);
|
||||
|
||||
// any introduction instance is invoked once only
|
||||
((ICountingIntroduction)outerProxy).Inc();
|
||||
Assert.AreEqual(1, countingMixin.Counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright 2002-2009 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
|
||||
|
||||
using System;
|
||||
using AopAlliance.Aop;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Spring.Aop.Support
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <author>Erich Eichinger</author>
|
||||
[TestFixture]
|
||||
public class DefaultIntroductionAdvisorTests
|
||||
{
|
||||
public interface IBaseInterface { }
|
||||
public interface IDerivedInterface : IBaseInterface { }
|
||||
|
||||
private class TestIntroductionAdvice : IDerivedInterface, IAdvice
|
||||
{
|
||||
private object equalsToObject;
|
||||
|
||||
public void SetEqualsToObject(object other)
|
||||
{
|
||||
equalsToObject = other;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return object.Equals(equalsToObject, obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EqualsOnAdviceEqualAndInterfacesEqual()
|
||||
{
|
||||
TestIntroductionAdvice to1 = new TestIntroductionAdvice();
|
||||
TestIntroductionAdvice to2 = new TestIntroductionAdvice();
|
||||
to1.SetEqualsToObject(to2);
|
||||
to2.SetEqualsToObject(to1);
|
||||
|
||||
DefaultIntroductionAdvisor a1 = new DefaultIntroductionAdvisor(to1);
|
||||
DefaultIntroductionAdvisor a2 = new DefaultIntroductionAdvisor(to2);
|
||||
bool result = a1.Equals(a2);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentException), ExpectedMessage = "Type [Spring.Aop.Support.DefaultIntroductionAdvisorTests] is not an interface; cannot be used in an introduction.")]
|
||||
public void BailsIfInterfaceTypeIsNotAnInterface()
|
||||
{
|
||||
DefaultIntroductionAdvisor a = new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), this.GetType());
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentException), ExpectedMessage = "Introduction [Spring.Aop.Support.DefaultIntroductionAdvisorTests+TestIntroductionAdvice] does not implement interface 'System.ICloneable' specified in introduction advice.")]
|
||||
public void IntroductionMustImplementIntroducedInterfaces()
|
||||
{
|
||||
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), typeof(ICloneable));
|
||||
advisor.ValidateInterfaces();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BaseInterfacesAreValid()
|
||||
{
|
||||
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new TestIntroductionAdvice(), typeof(IBaseInterface));
|
||||
advisor.ValidateInterfaces();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,6 +210,7 @@
|
||||
<Compile Include="Aop\Support\ControlFlowPointcutTests.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Aop\Support\DefaultIntroductionAdvisorTests.cs" />
|
||||
<Compile Include="Aop\Support\DelegatingIntroductionInterceptorTests.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
||||
Reference in New Issue
Block a user