From c161b030caff104a02619d96b9cd6fda78a467d0 Mon Sep 17 00:00:00 2001
From: eeichinger
Date: Sun, 8 Mar 2009 12:58:06 +0000
Subject: [PATCH] Enabled support for nhibernate dynamic entities fixed
SPRNET-1174: Proxies dont implement methods of base interfaces of interfaces
fixed SPRNET-1182: defer target==null checking until actual joinpoint
invocation in proxy method implementations
---
.../Aop/Framework/AbstractMethodInvocation.cs | 28 +-
.../Aop/Framework/DynamicMethodInvocation.cs | 208 ++---
.../Framework/ReflectiveMethodInvocation.cs | 16 +-
.../Proxy/AbstractProxyMethodBuilder.cs | 45 +-
.../Proxy/AbstractProxyTypeBuilder.cs | 17 +-
src/Spring/Spring.Core/Util/AssertUtils.cs | 124 ++-
.../DynamicProxy/AbstractAopProxyTests.cs | 734 +++++++++++-------
.../DynamicProxy/CompositionAopProxyTests.cs | 3 +
.../Util/AssertUtilsTests.cs | 199 +++--
9 files changed, 941 insertions(+), 433 deletions(-)
diff --git a/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs b/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs
index 945a450d..f793712f 100644
--- a/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs
+++ b/src/Spring/Spring.Aop/Aop/Framework/AbstractMethodInvocation.cs
@@ -130,7 +130,9 @@ namespace Spring.Aop.Framework
{
#region Sanity Check
- AssertUtils.ArgumentNotNull(target, "target");
+ // EE: There is not necessarily always a target - e.g. for DynamicEntities
+ // moved this check to InvokeJoinpoint()
+// AssertUtils.ArgumentNotNull(target, "target");
AssertUtils.ArgumentNotNull(method, "method");
#endregion
@@ -252,7 +254,8 @@ namespace Spring.Aop.Framework
{
if (this.interceptors == null ||
this.currentInterceptorIndex == this.interceptors.Count)
- {
+ {
+ AssertJoinpoint();
return InvokeJoinpoint();
}
object interceptor = this.interceptors[this.currentInterceptorIndex];
@@ -296,6 +299,27 @@ namespace Spring.Aop.Framework
protected abstract IMethodInvocation PrepareMethodInvocationForProceed(
IMethodInvocation invocation);
+ ///
+ /// Performs sanity checks, whether the actual joinpoint may be invoked
+ ///
+ ///
+ /// By default checks that the underlying target is not null and the called method is implemented
+ /// by the target's type.
+ ///
+ /// if is null.
+ /// if the 's type does not implement .
+ protected virtual void AssertJoinpoint()
+ {
+ AssertUtils.ArgumentNotNull(target, "target");
+// if (this.method != null
+// && !this.method.DeclaringType.IsAssignableFrom(target.GetType()))
+// {
+// // This means the target type doesn't implement the interface.
+// // Since no interceptor has handled the call, we throw a sensible exception here.
+// throw new NotSupportedException(string.Format("Interface method '{0}.{1}()' was not handled by any interceptor and the underlying target type '{2}' does not implement this method.", method.DeclaringType.FullName, method.Name, target.GetType().FullName));
+// }
+ }
+
///
/// Invokes the joinpoint.
///
diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs
index 9021f9ac..4e9f6fce 100644
--- a/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs
+++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicMethodInvocation.cs
@@ -1,5 +1,5 @@
-#region License
-
+#region License
+
/*
* Copyright © 2002-2005 the original author or authors.
*
@@ -14,85 +14,89 @@
* 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.Collections;
-using System.Reflection;
-
-using Spring.Util;
-using Spring.Reflection.Dynamic;
-using AopAlliance.Intercept;
-
-#endregion
-
-namespace Spring.Aop.Framework
-{
- ///
- /// Invokes a target method using dynamic reflection.
- ///
- ///
- /// Aleksandar Seovic
- /// Bruno Baia
- [Serializable]
- public class DynamicMethodInvocation : AbstractMethodInvocation
- {
- ///
- /// The method invocation that is to be invoked on the proxy.
- ///
- protected MethodInfo proxyMethod;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- /// The AOP proxy.
- /// The target object.
- /// The target method proxied.
- /// The method to invoke on proxy.
- /// The target method's arguments.
- ///
- /// The of the target object.
- ///
- /// The list of interceptors that are to be applied. May be
- /// .
- ///
- ///
- /// If any of the or
- /// parameters is .
- ///
- public DynamicMethodInvocation(
- object proxy, object target, MethodInfo method, MethodInfo proxyMethod,
- object[] arguments, Type targetType, IList interceptors)
- : base(proxy, target, method, arguments, targetType, interceptors)
- {
- this.proxyMethod = proxyMethod;
- }
-
- ///
- /// Invokes the joinpoint using dynamic reflection.
- ///
- ///
- ///
- /// Subclasses can override this to use custom invocation.
- ///
- ///
- ///
- /// The return value of the invocation of the joinpoint.
- ///
- ///
- /// If invoking the joinpoint resulted in an exception.
- ///
- ///
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+using Spring.Util;
+using Spring.Reflection.Dynamic;
+using AopAlliance.Intercept;
+
+#endregion
+
+namespace Spring.Aop.Framework
+{
+ ///
+ /// Invokes a target method using dynamic reflection.
+ ///
+ ///
+ /// Aleksandar Seovic
+ /// Bruno Baia
+ [Serializable]
+ public class DynamicMethodInvocation : AbstractMethodInvocation
+ {
+ ///
+ /// The method invocation that is to be invoked on the proxy.
+ ///
+ protected MethodInfo proxyMethod;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ /// The AOP proxy.
+ /// The target object.
+ /// The target method proxied.
+ /// The method to invoke on proxy.
+ /// The target method's arguments.
+ ///
+ /// The of the target object.
+ ///
+ /// The list of interceptors that are to be applied. May be
+ /// .
+ ///
+ ///
+ /// If any of the or
+ /// parameters is .
+ ///
+ public DynamicMethodInvocation(
+ object proxy, object target, MethodInfo method, MethodInfo proxyMethod,
+ object[] arguments, Type targetType, IList interceptors)
+ : base(proxy, target, method, arguments, targetType, interceptors)
+ {
+ this.proxyMethod = proxyMethod;
+ }
+
+ ///
+ /// Invokes the joinpoint using dynamic reflection.
+ ///
+ ///
+ ///
+ /// Subclasses can override this to use custom invocation.
+ ///
+ ///
+ ///
+ /// The return value of the invocation of the joinpoint.
+ ///
+ ///
+ /// If invoking the joinpoint resulted in an exception.
+ ///
+ ///
protected override object InvokeJoinpoint()
- {
- IDynamicMethod targetMethod = (this.proxyMethod == null) ? new SafeMethod(method) : new SafeMethod(proxyMethod);
- try
- {
+ {
+ MethodInfo targetMethodInfo = ((this.proxyMethod == null)) ? method : this.proxyMethod;
+
+ IDynamicMethod targetMethod = new SafeMethod(targetMethodInfo);
+
+ try
+ {
+ AssertUtils.Understands(target, "target", targetMethodInfo);
return targetMethod.Invoke(target, arguments);
}
// Only happens if fallback to standard reflection.
@@ -100,26 +104,26 @@ namespace Spring.Aop.Framework
{
throw ReflectionUtils.UnwrapTargetInvocationException(ex);
}
- }
-
- ///
- /// Creates a new instance
- /// from the specified and
- /// increments the interceptor index.
- ///
- ///
- /// The current instance.
- ///
- ///
- /// The new instance to use.
- ///
- protected override IMethodInvocation PrepareMethodInvocationForProceed(IMethodInvocation invocation)
- {
- DynamicMethodInvocation rmi = new DynamicMethodInvocation(
- this.proxy, this.target, this.method, this.proxyMethod, this.arguments, this.targetType, this.interceptors);
- rmi.currentInterceptorIndex = this.currentInterceptorIndex + 1;
-
- return rmi;
- }
- }
+ }
+
+ ///
+ /// Creates a new instance
+ /// from the specified and
+ /// increments the interceptor index.
+ ///
+ ///
+ /// The current instance.
+ ///
+ ///
+ /// The new instance to use.
+ ///
+ protected override IMethodInvocation PrepareMethodInvocationForProceed(IMethodInvocation invocation)
+ {
+ DynamicMethodInvocation rmi = new DynamicMethodInvocation(
+ this.proxy, this.target, this.method, this.proxyMethod, this.arguments, this.targetType, this.interceptors);
+ rmi.currentInterceptorIndex = this.currentInterceptorIndex + 1;
+
+ return rmi;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs b/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs
index 152359f3..899244c8 100644
--- a/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs
+++ b/src/Spring/Spring.Aop/Aop/Framework/ReflectiveMethodInvocation.cs
@@ -91,21 +91,17 @@ namespace Spring.Aop.Framework
protected override object InvokeJoinpoint()
{
try
- {
- if (proxyMethod == null)
- {
- return method.Invoke(target, arguments);
- }
- else
- {
- return proxyMethod.Invoke(target, arguments);
- }
+ {
+ MethodInfo targetMethodInfo = ((this.proxyMethod == null)) ? method : this.proxyMethod;
+
+ AssertUtils.Understands(target, "target", targetMethodInfo);
+ return targetMethodInfo.Invoke(target, arguments);
}
catch (TargetInvocationException ex)
{
throw ReflectionUtils.UnwrapTargetInvocationException(ex);
}
- }
+ }
///
/// Creates a new instance
diff --git a/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs b/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs
index 2fc128f9..391a2d88 100644
--- a/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs
+++ b/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs
@@ -275,7 +275,14 @@ namespace Spring.Proxy
// setup target object for call
PushTarget(il);
- // cast to type method is on
+ // TODO (EE): check for null and interface type and throw NotSupportedException
+ LocalBuilder targetRef = il.DeclareLocal(typeof(object));
+ il.Emit(OpCodes.Stloc, targetRef);
+
+ CallAssertUnderstands(il, interfaceMethod, targetRef, "target");
+
+ // setup target and cast to type method is on
+ il.Emit(OpCodes.Ldloc, targetRef);
il.Emit(OpCodes.Castclass, interfaceMethod.DeclaringType);
// setup parameters for call
@@ -289,6 +296,17 @@ namespace Spring.Proxy
il.EmitCall(OpCodes.Callvirt, interfaceMethod, null);
}
+ private void CallAssertUnderstands(ILGenerator il, MethodInfo method, LocalBuilder targetRef, string targetName)
+ {
+ // AssertArgumentType
+ il.Emit(OpCodes.Ldloc, targetRef);
+ il.Emit(OpCodes.Ldstr, targetName);
+ il.Emit(OpCodes.Ldtoken, method.DeclaringType);
+ il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }));
+// il.Emit(OpCodes.Ldstr, string.Format("Interface method '{0}.{1}()' was not handled by any interceptor and the target does not implement this method.", method.DeclaringType.FullName, method.Name));
+ il.Emit(OpCodes.Call, typeof(AssertUtils).GetMethod("Understands", new Type[] { typeof(object), typeof(string), typeof(Type) }));
+ }
+
///
/// Calls base method directly.
///
@@ -299,6 +317,16 @@ namespace Spring.Proxy
// setup proxy instance for call
PushProxy(il);
+ // TODO (EE): check for null and interface type and throw NotSupportedException
+ LocalBuilder targetRef = il.DeclareLocal(typeof(object));
+ il.Emit(OpCodes.Stloc, targetRef);
+
+ CallAssertUnderstands(il, method, targetRef, "base");
+
+ // setup target and cast to type method is on
+ il.Emit(OpCodes.Ldloc, targetRef);
+ il.Emit(OpCodes.Castclass, method.DeclaringType);
+
// setup parameters for call
ParameterInfo[] paramArray = method.GetParameters();
for (int i = 0; i < paramArray.Length; i++)
@@ -343,6 +371,21 @@ namespace Spring.Proxy
il.MarkLabel(jmpMethodReturn);
}
+ ///
+ /// Generates code that throws .
+ ///
+ /// IL generator to use.
+ /// the type of the exception to throw
+ /// Error message to use.
+ protected static void EmitThrowException(ILGenerator il, Type exceptionType, string message)
+ {
+ ConstructorInfo NewException = exceptionType.GetConstructor(new Type[] { typeof(string) });
+
+ il.Emit(OpCodes.Ldstr, message);
+ il.Emit(OpCodes.Newobj, NewException);
+ il.Emit(OpCodes.Throw);
+ }
+
#endregion
}
}
diff --git a/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs b/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs
index d9206928..c3797747 100644
--- a/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs
+++ b/src/Spring/Spring.Core/Proxy/AbstractProxyTypeBuilder.cs
@@ -27,6 +27,7 @@ using System.Reflection.Emit;
using System.Runtime.Serialization;
using Common.Logging;
+using Spring.Collections;
using Spring.Core.TypeResolution;
using Spring.Util;
@@ -964,7 +965,7 @@ namespace Spring.Proxy
///
protected virtual Type[] GetProxiableInterfaces(Type[] interfaces)
{
- ArrayList proxiableInterfaces = new ArrayList();
+ ArrayList proxiableInterfaces = new ArrayList();
foreach(Type intf in interfaces)
{
@@ -972,7 +973,19 @@ namespace Spring.Proxy
!IsSpecialInterface(intf) &&
ReflectionUtils.IsTypeVisible(intf, DynamicProxyManager.ASSEMBLY_NAME))
{
- proxiableInterfaces.Add(intf);
+ if (!proxiableInterfaces.Contains(intf))
+ {
+ proxiableInterfaces.Add(intf);
+ }
+
+ Type[] baseInterfaces = intf.GetInterfaces();
+ foreach (Type baseInterface in baseInterfaces)
+ {
+ if (!proxiableInterfaces.Contains(baseInterface))
+ {
+ proxiableInterfaces.Add(baseInterface);
+ }
+ }
}
}
diff --git a/src/Spring/Spring.Core/Util/AssertUtils.cs b/src/Spring/Spring.Core/Util/AssertUtils.cs
index 6b252d51..e1baebd6 100644
--- a/src/Spring/Spring.Core/Util/AssertUtils.cs
+++ b/src/Spring/Spring.Core/Util/AssertUtils.cs
@@ -22,7 +22,11 @@
using System;
using System.Collections;
-using System.Globalization;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Proxies;
+using System.Runtime.Serialization;
#endregion
@@ -37,9 +41,125 @@ namespace Spring.Util
///
///
/// Aleksandar Seovic
+ /// Erich Eichinger
public sealed class AssertUtils
{
- ///
+ ///
+ /// Checks, whether may be invoked on .
+ /// Supports testing transparent proxies.
+ ///
+ ///the target instance or null
+ ///the name of the target to be used in error messages
+ ///the method to test for
+ ///
+ /// if is null
+ ///
+ ///
+ /// if it is not possible to invoke on
+ ///
+ public static void Understands(object target, string targetName, MethodBase method)
+ {
+ ArgumentNotNull(method, "method");
+
+ if (target==null )
+ {
+ if (method.IsStatic)
+ {
+ return;
+ }
+ throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Target '{0}' is null and target method '{1}.{2}' is not static.", targetName, method.DeclaringType.FullName, method.Name));
+ }
+
+ Understands(target, targetName, method.DeclaringType);
+ }
+
+ ///
+ /// checks, whether supports the methods of .
+ /// Supports testing transparent proxies.
+ ///
+ ///the target instance or null
+ ///the name of the target to be used in error messages
+ ///the type to test for
+ ///
+ /// if is null
+ ///
+ ///
+ /// if it is not possible to invoke methods of
+ /// type on
+ ///
+ public static void Understands(object target, string targetName, Type requiredType)
+ {
+ ArgumentNotNull(requiredType, "requiredType");
+
+ if (target == null)
+ {
+ throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Target '{0}' is null.", targetName));
+ }
+
+ Type targetType;
+ if (RemotingServices.IsTransparentProxy(target))
+ {
+ RealProxy rp = RemotingServices.GetRealProxy(target);
+ IRemotingTypeInfo rti = rp as IRemotingTypeInfo;
+ if (rti != null)
+ {
+ if (rti.CanCastTo(requiredType, target))
+ {
+ return;
+ }
+ throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Target '{0}' is a transparent proxy that does not support methods of '{1}'.", targetName, requiredType.FullName));
+ }
+ targetType = rp.GetProxiedType();
+ }
+ else
+ {
+ targetType = target.GetType();
+ }
+
+ if (!requiredType.IsAssignableFrom(targetType))
+ {
+ throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Target '{0}' of type '{1}' does not support methods of '{2}'.", targetName, targetType, requiredType.FullName));
+ }
+ }
+
+ #region checking casts on transparent proxies (From BCL via Reflector)
+ // private static bool CheckCast(RealProxy rp, Type castType)
+// {
+// bool flag = false;
+// if (castType == typeof(object))
+// {
+// return true;
+// }
+// if (!castType.IsInterface && !castType.IsMarshalByRef)
+// {
+// return false;
+// }
+// if (castType != typeof(IObjectReference))
+// {
+// IRemotingTypeInfo typeInfo = rp as IRemotingTypeInfo;
+// if (typeInfo != null)
+// {
+// return typeInfo.CanCastTo(castType, rp.GetTransparentProxy());
+// }
+// Identity identityObject = rp.IdentityObject;
+// if (identityObject != null)
+// {
+// ObjRef objectRef = identityObject.ObjectRef;
+// if (objectRef != null)
+// {
+// typeInfo = objectRef.TypeInfo;
+// if (typeInfo != null)
+// {
+// flag = typeInfo.CanCastTo(castType, rp.GetTransparentProxy());
+// }
+// }
+// }
+// }
+// return flag;
+ // }
+ #endregion
+
+ ///
/// Checks the value of the supplied and throws an
/// if it is .
///
diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs
index 49c4dcbb..db84f77c 100644
--- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs
+++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs
@@ -34,6 +34,7 @@ using System.Runtime.Remoting;
using AopAlliance.Aop;
using AopAlliance.Intercept;
+using Rhino.Mocks;
using Spring.Aop.Target;
using Spring.Aop.Framework;
using Spring.Aop.Framework.Adapter;
@@ -71,7 +72,7 @@ namespace Spring.Aop.Framework.DynamicProxy
[TestFixtureSetUp]
public void FixtureSetUp()
{
-// SystemUtils.RegisterLoadedAssemblyResolver();
+ // SystemUtils.RegisterLoadedAssemblyResolver();
}
[SetUp]
@@ -249,8 +250,136 @@ namespace Spring.Aop.Framework.DynamicProxy
Assert.AreEqual(name, to.Name);
}
+ #region ImplementsInterfaceHierarchy Types
+
+ public interface ITestPerson
+ {
+ long Id { get; set; }
+ string Name { get; set; }
+ }
+
+ public interface ITestCustomer : ITestPerson
+ {
+ string Company { get; set; }
+ }
+
+ #endregion
+
+ [Test(Description = "http://jira.springframework.org/browse/SPRNET-1174")]
+ public void ImplementsInterfaceHierarchy()
+ {
+ MockRepository mocks = new MockRepository();
+
+ IMethodInterceptor mi = (IMethodInterceptor)mocks.DynamicMock(typeof(IMethodInterceptor));
+
+ Expect.Call(mi.Invoke(null)).IgnoreArguments().Return((long)5);
+ Expect.Call(mi.Invoke(null)).IgnoreArguments().Return("Customer Name");
+ Expect.Call(mi.Invoke(null)).IgnoreArguments().Return("Customer Company");
+ mocks.ReplayAll();
+
+ AdvisedSupport advised = new AdvisedSupport();
+ advised.AddAdvice(mi);
+ advised.Interfaces = new Type[] { typeof(ITestCustomer) };
+
+ ITestCustomer to = CreateProxy(advised) as ITestCustomer;
+ Assert.IsNotNull(to);
+ Assert.AreEqual((long)5, to.Id, "Incorrect Id");
+ Assert.AreEqual("Customer Name", to.Name, "Incorrect Name");
+ Assert.AreEqual("Customer Company", to.Company, "Incorrect Company");
+
+ mocks.VerifyAll();
+ }
+
[Test]
- public void InterceptorInvokedWithNoTarget()
+ [ExpectedException(typeof(NotSupportedException)
+ , ExpectedMessage = "Target 'target' is null.")]
+ public void Does_proxy_interfacemethods_without_implementation_and_by_default_throws_NotSupportedException()
+ {
+ AdvisedSupport advised = new AdvisedSupport();
+ advised.TargetSource = new DynamicTargetSource(typeof(object), null);
+ advised.Interfaces = new Type[] { typeof(ITestObject) };
+
+ ITestObject proxy = CreateProxy(advised) as ITestObject;
+ Assert.IsNotNull(proxy);
+
+ proxy.GetDescription();
+ }
+
+ [Test]
+ public void Does_proxy_interfacemethods_without_implementation_and_delegates_to_interceptors()
+ {
+ DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor();
+ DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null);
+
+ AdvisedSupport advised = new AdvisedSupport();
+ advised.TargetSource = targetSource;
+ advised.Interfaces = new Type[] { typeof(ITestObject) };
+ advised.AddAdvice(invocationInterceptor);
+ ITestObject proxy = CreateProxy(advised) as ITestObject;
+ Assert.IsNotNull(proxy);
+
+ // target null, call handled by interceptor
+ targetSource.Target = null;
+ invocationInterceptor.CallProceed = false;
+ proxy.GetDescription();
+ Assert.AreEqual("GetDescription", invocationInterceptor.LastMethodInvocation.Method.Name);
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException), MatchType=MessageMatch.Contains, UserMessage="'target'")]
+ public void Does_proxy_interfacemethods_without_implementation_and_throws_ArgumentNullException_On_NullTarget()
+ {
+ DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor();
+ DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null);
+
+ AdvisedSupport advised = new AdvisedSupport();
+ advised.TargetSource = targetSource;
+ advised.Interfaces = new Type[] { typeof(ITestObject) };
+ advised.AddAdvice(invocationInterceptor);
+ ITestObject proxy = CreateProxy(advised) as ITestObject;
+ Assert.IsNotNull(proxy);
+
+ // target null, call not handled by interceptor
+ targetSource.Target = null;
+ invocationInterceptor.CallProceed = true;
+ proxy.GetDescription();
+ }
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException)
+ , ExpectedMessage = "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'.")]
+ public void Does_proxy_interfacemethods_without_implementation_and_throws_NotSupportedException_On_Incompatible_Target()
+ {
+ DynamicInvocationTestInterceptor invocationInterceptor = new DynamicInvocationTestInterceptor();
+ DynamicTargetSource targetSource = new DynamicTargetSource(typeof(object), null);
+
+ AdvisedSupport advised = new AdvisedSupport();
+ advised.TargetSource = targetSource;
+ advised.Interfaces = new Type[] { typeof(ITestObject) };
+ advised.AddAdvice(invocationInterceptor);
+ ITestObject proxy = CreateProxy(advised) as ITestObject;
+ Assert.IsNotNull(proxy);
+
+ // target incompatible, call not handled by interceptor
+ targetSource.Target = new object();
+ invocationInterceptor.CallProceed = true;
+ proxy.GetDescription();
+ }
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException)
+ , ExpectedMessage = "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'.")]
+ public void NoInterceptorWithNoTarget()
+ {
+ AdvisedSupport advised = new AdvisedSupport();
+ advised.Interfaces = new Type[] { typeof(ITestObject) };
+
+ ITestObject to = CreateProxy(advised) as ITestObject;
+ to.GetDescription();
+ }
+
+ [Test]
+ public void InterceptorHandledCallWithNoTarget()
{
int age = 26;
DynamicMock mock = new DynamicMock(typeof(IMethodInterceptor));
@@ -267,6 +396,20 @@ namespace Spring.Aop.Framework.DynamicProxy
mock.Verify();
}
+ [Test]
+ [ExpectedException(typeof(NotSupportedException)
+ , ExpectedMessage = "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'.")]
+ public void InterceptorUnhandledCallWithNoTarget()
+ {
+ AdvisedSupport advised = new AdvisedSupport();
+ advised.AddAdvice(new NopInterceptor());
+ advised.Interfaces = new Type[] { typeof(ITestObject) };
+
+ ITestObject to = CreateProxy(advised) as ITestObject;
+ Assert.IsNotNull(to);
+ to.GetDescription();
+ }
+
[Test]
public void ProxyAProxy()
{
@@ -492,10 +635,10 @@ namespace Spring.Aop.Framework.DynamicProxy
public interface IRefOutTestObject
{
- int DoIt(int valueType, TestObject obj, EnumValue enumValue,
+ int DoIt(int valueType, TestObject obj, EnumValue enumValue,
ref bool refValueType, out int outValueType,
ref String refObj, out TestObject outObj,
- ref EnumValue refEnum, out EnumValue outEnum,
+ ref EnumValue refEnum, out EnumValue outEnum,
ref Guid refGuid, out Guid outGuid);
}
@@ -504,7 +647,7 @@ namespace Spring.Aop.Framework.DynamicProxy
public int DoIt(int valueType, TestObject obj, EnumValue enumValue,
ref bool refValueType, out int outValueType,
ref String refObj, out TestObject outObj,
- ref EnumValue refEnum, out EnumValue outEnum,
+ ref EnumValue refEnum, out EnumValue outEnum,
ref Guid refGuid, out Guid outGuid)
{
valueType++;
@@ -652,7 +795,7 @@ namespace Spring.Aop.Framework.DynamicProxy
[Test]
public void InterceptGenericMethod()
{
- AbstractProxyTypeBuilderTests.ClassWithGenericMethod target =
+ AbstractProxyTypeBuilderTests.ClassWithGenericMethod target =
new AbstractProxyTypeBuilderTests.ClassWithGenericMethod();
mockTargetSource.SetTarget(target);
@@ -692,7 +835,7 @@ namespace Spring.Aop.Framework.DynamicProxy
[Test]
public void InterceptGenericInterface()
{
- AbstractProxyTypeBuilderTests.ClassThatImplementsGenericInterface target =
+ AbstractProxyTypeBuilderTests.ClassThatImplementsGenericInterface target =
new AbstractProxyTypeBuilderTests.ClassThatImplementsGenericInterface();
mockTargetSource.SetTarget(target);
@@ -702,7 +845,7 @@ namespace Spring.Aop.Framework.DynamicProxy
advised.TargetSource = mockTargetSource;
advised.AddAdvice(ni);
- AbstractProxyTypeBuilderTests.GenericInterface proxy =
+ AbstractProxyTypeBuilderTests.GenericInterface proxy =
CreateProxy(advised) as AbstractProxyTypeBuilderTests.GenericInterface;
Assert.IsNotNull(proxy);
@@ -1034,21 +1177,21 @@ namespace Spring.Aop.Framework.DynamicProxy
pf.AddAdvice(new CountingBeforeAdvice());
pf.AddAdvice(new CountingAfterReturningAdvice());
pf.AddAdvice(cta);
- IPerson p = (IPerson) CreateAopProxy(pf).GetProxy();
+ IPerson p = (IPerson)CreateAopProxy(pf).GetProxy();
p.Echo(null);
Assert.AreEqual(0, cta.GetCalls());
- try
+ try
{
p.Echo(new Exception());
}
- catch (Exception)
+ catch (Exception)
{
}
Assert.AreEqual(1, cta.GetCalls());
// Will throw exception if it fails
- IPerson p2 = (IPerson) SerializationTestUtils.SerializeAndDeserialize(p);
+ IPerson p2 = (IPerson)SerializationTestUtils.SerializeAndDeserialize(p);
Assert.AreNotSame(p, p2);
Assert.AreEqual(p.GetName(), p2.GetName());
Assert.AreEqual(p.GetAge(), p2.GetAge());
@@ -1070,10 +1213,10 @@ namespace Spring.Aop.Framework.DynamicProxy
p2.GetAge();
Assert.AreEqual(1, ni.Count);
- cta = (CountingThrowsAdvice) a2.Advisors[3].Advice;
+ cta = (CountingThrowsAdvice)a2.Advisors[3].Advice;
p2.Echo(null);
Assert.AreEqual(1, cta.GetCalls());
- try
+ try
{
p2.Echo(new Exception());
}
@@ -1091,7 +1234,7 @@ namespace Spring.Aop.Framework.DynamicProxy
/// and don't conflict.
///
[Test]
- public void OneAdvisedObjectCallsAnother()
+ public void OneAdvisedObjectCallsAnother()
{
int age1 = 33;
int age2 = 37;
@@ -1104,7 +1247,7 @@ namespace Spring.Aop.Framework.DynamicProxy
pf1.AddAdvice(0, di1);
pf1.AddAdvice(1, new ProxyMatcherInterceptor());
pf1.AddAdvice(2, new MethodInvocationMatcherInterceptor());
- ITestObject advised1 = (ITestObject) pf1.GetProxy();
+ ITestObject advised1 = (ITestObject)pf1.GetProxy();
advised1.Age = age1; // = 1 invocation
TestObject target2 = new TestObject();
@@ -1114,7 +1257,7 @@ namespace Spring.Aop.Framework.DynamicProxy
pf2.AddAdvice(0, di2);
pf2.AddAdvice(1, new ProxyMatcherInterceptor());
pf2.AddAdvice(2, new MethodInvocationMatcherInterceptor());
- ITestObject advised2 = (ITestObject) CreateProxy(pf2);
+ ITestObject advised2 = (ITestObject)CreateProxy(pf2);
advised2.Age = age2;
advised1.Spouse = advised2; // = 2 invocations
@@ -1244,7 +1387,7 @@ namespace Spring.Aop.Framework.DynamicProxy
AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) });
advised.Target = raw;
- ITestObject to = (ITestObject) CreateProxy(advised);
+ ITestObject to = (ITestObject)CreateProxy(advised);
Assert.IsTrue(to.Spouse == to, "this return is wrapped in proxy");
}
@@ -1256,10 +1399,10 @@ namespace Spring.Aop.Framework.DynamicProxy
}
}
- #endregion
+ #endregion
[Test]
- public void TargetThrowsException()
+ public void TargetThrowsException()
{
Exception expectedException = new ApplicationException();
@@ -1268,13 +1411,13 @@ namespace Spring.Aop.Framework.DynamicProxy
advised.Target = new TestObject();
IAopProxy aop = CreateAopProxy(advised);
- try
+ try
{
- ITestObject to = (ITestObject) aop.GetProxy();
+ ITestObject to = (ITestObject)aop.GetProxy();
to.Exceptional(expectedException);
Assert.Fail("Should have thrown exception raised by target");
}
- catch (Exception ex)
+ catch (Exception ex)
{
Assert.AreEqual(expectedException, ex, "exception matches");
}
@@ -1324,60 +1467,60 @@ namespace Spring.Aop.Framework.DynamicProxy
#endregion
// TODO : Introduction tests
-/*
- [Test(Description = "Test stateful interceptor")]
- public void MixinWithIntroductionAdvisor()
- {
- TestObject to = new TestObject();
- AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) });
- advised.AddAdvisor(new LockMixinAdvisor());
- advised.Target = to;
+ /*
+ [Test(Description = "Test stateful interceptor")]
+ public void MixinWithIntroductionAdvisor()
+ {
+ TestObject to = new TestObject();
+ AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) });
+ advised.AddAdvisor(new LockMixinAdvisor());
+ advised.Target = to;
- CheckTestObjectIntroduction(advised);
- }
+ CheckTestObjectIntroduction(advised);
+ }
- [Test]
- public void MixinWithIntroductionInfo()
- {
- TestObject to = new TestObject();
- AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) });
- advised.AddAdvice(new LockMixin());
- advised.Target = to;
+ [Test]
+ public void MixinWithIntroductionInfo()
+ {
+ TestObject to = new TestObject();
+ AdvisedSupport advised = new AdvisedSupport(new Type[] { typeof(ITestObject) });
+ advised.AddAdvice(new LockMixin());
+ advised.Target = to;
- CheckTestObjectIntroduction(advised);
- }
+ CheckTestObjectIntroduction(advised);
+ }
- private void CheckTestObjectIntroduction(AdvisedSupport advised)
- {
- int newAge = 65;
+ private void CheckTestObjectIntroduction(AdvisedSupport advised)
+ {
+ int newAge = 65;
- ITestObject ito = (ITestObject) CreateProxy(advised);
- ito.Age = newAge;
- Assert.IsTrue(ito.Age == newAge);
+ ITestObject ito = (ITestObject) CreateProxy(advised);
+ ito.Age = newAge;
+ Assert.IsTrue(ito.Age == newAge);
- ILockable lockable = (ILockable) ito;
- Assert.IsFalse(lockable.Locked());
- lockable.DoLock();
+ ILockable lockable = (ILockable) ito;
+ Assert.IsFalse(lockable.Locked());
+ lockable.DoLock();
- Assert.IsTrue(ito.Age == newAge);
- try
- {
- ito.Age = 1;
- Assert.Fail("Setters should fail when locked");
- }
- catch (LockedException)
- {
- // ok
- }
- Assert.IsTrue(ito.Age == newAge);
+ Assert.IsTrue(ito.Age == newAge);
+ try
+ {
+ ito.Age = 1;
+ Assert.Fail("Setters should fail when locked");
+ }
+ catch (LockedException)
+ {
+ // ok
+ }
+ Assert.IsTrue(ito.Age == newAge);
- // Unlock
- Assert.IsTrue(lockable.Locked());
- lockable.Unlock();
- ito.Age = 1;
- Assert.IsTrue(ito.Age == 1);
- }
-*/
+ // Unlock
+ Assert.IsTrue(lockable.Locked());
+ lockable.Unlock();
+ ito.Age = 1;
+ Assert.IsTrue(ito.Age == 1);
+ }
+ */
#region MultipleProceedCalls
@@ -1668,33 +1811,33 @@ namespace Spring.Aop.Framework.DynamicProxy
}
// TODO : Opaque can be implemented if really usefull (To increase performance)
-/*
- public void testCanPreventCastToAdvisedUsingOpaque()
- {
- TestObject target = new TestObject();
- ProxyFactory pf = new ProxyFactory(target);
- pf.Interfaces = new Type[] { typeof(ITestObject) };
- pf.AddAdvice(new NopInterceptor());
- CountingBeforeAdvice mba = new CountingBeforeAdvice();
- NameMatchMethodPointcut nmmp = new NameMatchMethodPointcut();
- nmmp.MappedName = "set_Age";
- IAdvisor advisor = new DefaultPointcutAdvisor(nmmp, mba);
- pf.AddAdvisor(advisor);
- Assert.IsFalse(pf.Opaque, "Opaque defaults to false");
- pf.Opaque = true;
- Assert.IsTrue(pf.Opaque, "Opaque now true for this config");
- ITestObject proxied = (ITestObject) CreateProxy(pf);
- proxied.Age = 10;
- Assert.AreEqual(10, proxied.Age);
- Assert.AreEqual(1, mba.GetCalls());
+ /*
+ public void testCanPreventCastToAdvisedUsingOpaque()
+ {
+ TestObject target = new TestObject();
+ ProxyFactory pf = new ProxyFactory(target);
+ pf.Interfaces = new Type[] { typeof(ITestObject) };
+ pf.AddAdvice(new NopInterceptor());
+ CountingBeforeAdvice mba = new CountingBeforeAdvice();
+ NameMatchMethodPointcut nmmp = new NameMatchMethodPointcut();
+ nmmp.MappedName = "set_Age";
+ IAdvisor advisor = new DefaultPointcutAdvisor(nmmp, mba);
+ pf.AddAdvisor(advisor);
+ Assert.IsFalse(pf.Opaque, "Opaque defaults to false");
+ pf.Opaque = true;
+ Assert.IsTrue(pf.Opaque, "Opaque now true for this config");
+ ITestObject proxied = (ITestObject) CreateProxy(pf);
+ proxied.Age = 10;
+ Assert.AreEqual(10, proxied.Age);
+ Assert.AreEqual(1, mba.GetCalls());
- Assert.IsFalse(proxied is IAdvised, "Cannot be cast to Advised", );
- }
- */
+ Assert.IsFalse(proxied is IAdvised, "Cannot be cast to Advised", );
+ }
+ */
// TODO AdviceSupportListeners test
#region AdviceSupportListeners
-/*
+ /*
[Test]
public void AdviceSupportListeners()
{
@@ -1791,7 +1934,7 @@ namespace Spring.Aop.Framework.DynamicProxy
TestDynamicPointcutAdvisor dp = new TestDynamicPointcutAdvisor(new NopInterceptor(), "get_Age");
pf.AddAdvisor(dp);
pf.Target = to;
- ITestObject it = (ITestObject) CreateProxy(pf);
+ ITestObject it = (ITestObject)CreateProxy(pf);
Assert.AreEqual(dp.count, 0);
int age = it.Age;
Assert.IsNotNull(age); // avoid mono mcs CS0218
@@ -1872,7 +2015,7 @@ namespace Spring.Aop.Framework.DynamicProxy
TestStaticPointcutAdvisor sp = new TestStaticPointcutAdvisor(ni, "get_Age");
pf.AddAdvisor(sp);
pf.Target = to;
- ITestObject it = (ITestObject) CreateProxy(pf);
+ ITestObject it = (ITestObject)CreateProxy(pf);
Assert.AreEqual(ni.Count, 0);
int age = it.Age;
Assert.IsNotNull(age); // avoid mono mcs error CS0219
@@ -1907,106 +2050,106 @@ namespace Spring.Aop.Framework.DynamicProxy
#region CloneInvocationToProceedThreeTimes
// TODO ? ReflectiveMethodInvocation is not Cloneable
-/*
- [Test(Description="There are times when we want to call proceed() twice.")]
- public void CloneInvocationToProceedThreeTimes()
- {
- //We can do this if we clone the invocation.
+ /*
+ [Test(Description="There are times when we want to call proceed() twice.")]
+ public void CloneInvocationToProceedThreeTimes()
+ {
+ //We can do this if we clone the invocation.
- TestObject to = new TestObject();
- ProxyFactory pf = new ProxyFactory(to);
- pf.AddInterface(typeof(ITestObject));
+ TestObject to = new TestObject();
+ ProxyFactory pf = new ProxyFactory(to);
+ pf.AddInterface(typeof(ITestObject));
- TwoBirthdayAdvice twoBirthdayAdvice = new TwoBirthdayAdvice();
+ TwoBirthdayAdvice twoBirthdayAdvice = new TwoBirthdayAdvice();
- TwoBirthdayPointcutAdvisor sp = new TwoBirthdayPointcutAdvisor(twoBirthdayAdvice);
- pf.AddAdvisor(sp);
- ITestObject ito = (ITestObject)CreateProxy(pf);
+ TwoBirthdayPointcutAdvisor sp = new TwoBirthdayPointcutAdvisor(twoBirthdayAdvice);
+ pf.AddAdvisor(sp);
+ ITestObject ito = (ITestObject)CreateProxy(pf);
- int age = 20;
- ito.Age = age;
- Assert.AreEqual(age, ito.Age);
- // Should return the age before the third, AOP-induced birthday
- Assert.AreEqual(age + 2, ito.haveBirthday());
- // Return the final age produced by 3 birthdays
- Assert.AreEqual(age + 3, ito.Age);
- }
+ int age = 20;
+ ito.Age = age;
+ Assert.AreEqual(age, ito.Age);
+ // Should return the age before the third, AOP-induced birthday
+ Assert.AreEqual(age + 2, ito.haveBirthday());
+ // Return the final age produced by 3 birthdays
+ Assert.AreEqual(age + 3, ito.Age);
+ }
- private class TwoBirthdayPointcutAdvisor : StaticMethodMatcherPointcutAdvisor
- {
- public TwoBirthdayPointcutAdvisor(IAdvice advice)
- : base(advice)
- {
- }
+ private class TwoBirthdayPointcutAdvisor : StaticMethodMatcherPointcutAdvisor
+ {
+ public TwoBirthdayPointcutAdvisor(IAdvice advice)
+ : base(advice)
+ {
+ }
- public override bool Matches(MethodInfo method, Type targetType)
- {
- return "haveBirthday".Equals(method.Name);
- }
- }
+ public override bool Matches(MethodInfo method, Type targetType)
+ {
+ return "haveBirthday".Equals(method.Name);
+ }
+ }
- private class TwoBirthdayAdvice : IMethodInterceptor
- {
- public object Invoke(IMethodInvocation invocation)
- {
- // Clone the invocation to proceed three times
- // "The Moor's Last Sigh": this technology can cause premature aging
- IMethodInvocation clone1 = ((ReflectiveMethodInvocation)invocation).InvocableClone();
- IMethodInvocation clone2 = ((ReflectiveMethodInvocation)invocation).InvocableClone();
- clone1.Proceed();
- clone2.Proceed();
- return invocation.Proceed();
- }
- }
+ private class TwoBirthdayAdvice : IMethodInterceptor
+ {
+ public object Invoke(IMethodInvocation invocation)
+ {
+ // Clone the invocation to proceed three times
+ // "The Moor's Last Sigh": this technology can cause premature aging
+ IMethodInvocation clone1 = ((ReflectiveMethodInvocation)invocation).InvocableClone();
+ IMethodInvocation clone2 = ((ReflectiveMethodInvocation)invocation).InvocableClone();
+ clone1.Proceed();
+ clone2.Proceed();
+ return invocation.Proceed();
+ }
+ }
-// // We want to change the arguments on a clone: it shouldn't affect the original.
-// public void testCanChangeArgumentsIndependentlyOnClonedInvocation() throws Throwable
-// {
-// TestObject to = new TestObject();
-// ProxyFactory pc = new ProxyFactory(to);
-// pc.addInterface(typeof(ITestObject));
+ // // We want to change the arguments on a clone: it shouldn't affect the original.
+ // public void testCanChangeArgumentsIndependentlyOnClonedInvocation() throws Throwable
+ // {
+ // TestObject to = new TestObject();
+ // ProxyFactory pc = new ProxyFactory(to);
+ // pc.addInterface(typeof(ITestObject));
-// // Changes the name, then changes it back.
-// MethodInterceptor nameReverter = new MethodInterceptor() {
-// public Object invoke(MethodInvocation mi) throws Throwable {
-// MethodInvocation clone = ((ReflectiveMethodInvocation) mi).invocableClone();
-// String oldName = ((ITestObject) mi.getThis()).Name;
-// clone.getArguments()[0] = oldName;
-// // Original method invocation should be unaffected by changes to argument list of clone
-// mi.proceed();
-// return clone.proceed();
-// }
-// };
+ // // Changes the name, then changes it back.
+ // MethodInterceptor nameReverter = new MethodInterceptor() {
+ // public Object invoke(MethodInvocation mi) throws Throwable {
+ // MethodInvocation clone = ((ReflectiveMethodInvocation) mi).invocableClone();
+ // String oldName = ((ITestObject) mi.getThis()).Name;
+ // clone.getArguments()[0] = oldName;
+ // // Original method invocation should be unaffected by changes to argument list of clone
+ // mi.proceed();
+ // return clone.proceed();
+ // }
+ // };
-// class NameSaver implements MethodInterceptor {
-// private List names = new LinkedList();
+ // class NameSaver implements MethodInterceptor {
+ // private List names = new LinkedList();
-// public Object invoke(MethodInvocation mi) throws Throwable {
-// names.add(mi.getArguments()[0]);
-// return mi.proceed();
-// }
-// }
+ // public Object invoke(MethodInvocation mi) throws Throwable {
+ // names.add(mi.getArguments()[0]);
+ // return mi.proceed();
+ // }
+ // }
-// NameSaver saver = new NameSaver();
+ // NameSaver saver = new NameSaver();
-// pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, nameReverter));
-// pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, saver));
-// ITestObject it = (ITestObject) createProxy(pc);
+ // pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, nameReverter));
+ // pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, saver));
+ // ITestObject it = (ITestObject) createProxy(pc);
-// String name1 = "tony";
-// String name2 = "gordon";
+ // String name1 = "tony";
+ // String name2 = "gordon";
-// to.setName(name1);
-// Assert.AreEqual(name1, to.Name);
+ // to.setName(name1);
+ // Assert.AreEqual(name1, to.Name);
-// it.setName(name2);
-// // NameReverter saved it back
-// Assert.AreEqual(name1, it.Name);
-// Assert.AreEqual(2, saver.names.size());
-// Assert.AreEqual(name2, saver.names.get(0));
-// Assert.AreEqual(name1, saver.names.get(1));
-// }
-*/
+ // it.setName(name2);
+ // // NameReverter saved it back
+ // Assert.AreEqual(name1, it.Name);
+ // Assert.AreEqual(2, saver.names.size());
+ // Assert.AreEqual(name2, saver.names.get(0));
+ // Assert.AreEqual(name1, saver.names.get(1));
+ // }
+ */
#endregion
#region OverloadedMethodsWithDifferentAdvice
@@ -2021,7 +2164,7 @@ namespace Spring.Aop.Framework.DynamicProxy
NopInterceptor overloadInt = new NopInterceptor();
pf.AddAdvisor(new OverloadIntPointcutAdvisor(overloadInt));
- IOverloads proxy = (IOverloads) CreateProxy(pf);
+ IOverloads proxy = (IOverloads)CreateProxy(pf);
Assert.AreEqual(0, overloadInt.Count);
Assert.AreEqual(0, overloadVoid.Count);
@@ -2036,7 +2179,7 @@ namespace Spring.Aop.Framework.DynamicProxy
Assert.AreEqual(1, overloadVoid.Count);
}
- public interface IOverloads
+ public interface IOverloads
{
void Overload();
int Overload(int i);
@@ -2044,23 +2187,23 @@ namespace Spring.Aop.Framework.DynamicProxy
void NoAdvice();
}
- public class Overloads : IOverloads
+ public class Overloads : IOverloads
{
- public void Overload()
+ public void Overload()
{
}
- public int Overload(int i)
+ public int Overload(int i)
{
return i;
}
- public string Overload(string foo)
+ public string Overload(string foo)
{
return foo;
}
- public void NoAdvice()
+ public void NoAdvice()
{
}
}
@@ -2095,88 +2238,88 @@ namespace Spring.Aop.Framework.DynamicProxy
#endregion
// TODO : IAdvised.TargetSource is read only (no setter)
-/*
- [Test]
- public void ExistingProxyChangesTarget()
- {
- TestObject to1 = new TestObject();
- to1.Age = 33;
+ /*
+ [Test]
+ public void ExistingProxyChangesTarget()
+ {
+ TestObject to1 = new TestObject();
+ to1.Age = 33;
- TestObject to2 = new TestObject();
- to2.Age = 26;
- to2.Name = "Juergen";
- TestObject to3 = new TestObject();
- to3.Age = 37;
- ProxyFactory pf = new ProxyFactory(to1);
- NopInterceptor nop = new NopInterceptor();
- pf.AddAdvice(nop);
- ITestObject proxy = (ITestObject)CreateProxy(pf);
- Assert.AreEqual(nop.Count, 0);
- Assert.AreEqual(to1.Age, proxy.Age);
- Assert.AreEqual(nop.Count, 1);
- // Change to a new static target
- pf.Target = to2;
- Assert.AreEqual(to2.Age, proxy.Age);
- Assert.AreEqual(nop.Count, 2);
+ TestObject to2 = new TestObject();
+ to2.Age = 26;
+ to2.Name = "Juergen";
+ TestObject to3 = new TestObject();
+ to3.Age = 37;
+ ProxyFactory pf = new ProxyFactory(to1);
+ NopInterceptor nop = new NopInterceptor();
+ pf.AddAdvice(nop);
+ ITestObject proxy = (ITestObject)CreateProxy(pf);
+ Assert.AreEqual(nop.Count, 0);
+ Assert.AreEqual(to1.Age, proxy.Age);
+ Assert.AreEqual(nop.Count, 1);
+ // Change to a new static target
+ pf.Target = to2;
+ Assert.AreEqual(to2.Age, proxy.Age);
+ Assert.AreEqual(nop.Count, 2);
- // Change to a new dynamic target
- HotSwappableTargetSource hts = new HotSwappableTargetSource(to3);
- pf.TargetSource = hts;
- Assert.AreEqual(to3.Age, proxy.Age);
- Assert.AreEqual(nop.Count, 3);
- hts.Swap(to1);
- Assert.AreEqual(to1.Age, proxy.Age);
- to1.Name = "Colin";
- Assert.AreEqual(to1.Name, proxy.Name);
- Assert.AreEqual(nop.Count, 5);
+ // Change to a new dynamic target
+ HotSwappableTargetSource hts = new HotSwappableTargetSource(to3);
+ pf.TargetSource = hts;
+ Assert.AreEqual(to3.Age, proxy.Age);
+ Assert.AreEqual(nop.Count, 3);
+ hts.Swap(to1);
+ Assert.AreEqual(to1.Age, proxy.Age);
+ to1.Name = "Colin";
+ Assert.AreEqual(to1.Name, proxy.Name);
+ Assert.AreEqual(nop.Count, 5);
- // Change back, relying on casting to Advised
- IAdvised advised = (IAdvised)proxy;
- Assert.AreSame(hts, advised.TargetSource);
- SingletonTargetSource sts = new SingletonTargetSource(to2);
- advised.TargetSource = sts;
- Assert.AreEqual(to2.Name, proxy.Name);
- Assert.AreSame(sts, advised.TargetSource);
- Assert.AreEqual(to2.Age, proxy.Age);
- }
-
- [Test]
- public void ProxyIsBoundBeforeTargetSourceInvoked()
- {
- TestObject target = new TestObject();
- ProxyFactory pf = new ProxyFactory(target);
- pf.AddAdvice(new DebugInterceptor());
- pf.ExposeProxy = true;
- ITestObject proxy = (ITestObject) CreateProxy(pf);
- IAdvised config = (IAdvised) proxy;
- // This class just checks proxy is bound before getTarget() call
- config.setTargetSource(new TargetSource() {
- public Class getTargetClass() {
- return TestObject.class;
+ // Change back, relying on casting to Advised
+ IAdvised advised = (IAdvised)proxy;
+ Assert.AreSame(hts, advised.TargetSource);
+ SingletonTargetSource sts = new SingletonTargetSource(to2);
+ advised.TargetSource = sts;
+ Assert.AreEqual(to2.Name, proxy.Name);
+ Assert.AreSame(sts, advised.TargetSource);
+ Assert.AreEqual(to2.Age, proxy.Age);
}
- public boolean isStatic() {
- return false;
- }
+ [Test]
+ public void ProxyIsBoundBeforeTargetSourceInvoked()
+ {
+ TestObject target = new TestObject();
+ ProxyFactory pf = new ProxyFactory(target);
+ pf.AddAdvice(new DebugInterceptor());
+ pf.ExposeProxy = true;
+ ITestObject proxy = (ITestObject) CreateProxy(pf);
+ IAdvised config = (IAdvised) proxy;
+ // This class just checks proxy is bound before getTarget() call
+ config.setTargetSource(new TargetSource() {
+ public Class getTargetClass() {
+ return TestObject.class;
+ }
- public Object getTarget() throws Exception {
- Assert.AreEqual(proxy, AopContext.currentProxy());
- return target;
- }
+ public boolean isStatic() {
+ return false;
+ }
- public void releaseTarget(Object target) throws Exception {
- }
- });
+ public Object getTarget() throws Exception {
+ Assert.AreEqual(proxy, AopContext.currentProxy());
+ return target;
+ }
+
+ public void releaseTarget(Object target) throws Exception {
+ }
+ });
- // Just test anything: it will fail if context wasn't found
- Assert.AreEqual(0, proxy.Age);
- }
-*/
+ // Just test anything: it will fail if context wasn't found
+ Assert.AreEqual(0, proxy.Age);
+ }
+ */
#region BeforeAdvisorIsInvoked
[Test]
- public void BeforeAdvisorIsInvoked()
+ public void BeforeAdvisorIsInvoked()
{
CountingBeforeAdvice cba = new CountingBeforeAdvice();
IAdvisor matchesNoArgsAdvisor = new NoArgsMethodPointcutAdvisor(cba);
@@ -2272,7 +2415,7 @@ namespace Spring.Aop.Framework.DynamicProxy
#region BeforeAdviceThrowsException
[Test]
- public void BeforeAdviceThrowsException()
+ public void BeforeAdviceThrowsException()
{
ApplicationException aex = new ApplicationException();
CountingBeforeNonSetterAdvice ba = new CountingBeforeNonSetterAdvice(aex);
@@ -2293,12 +2436,12 @@ namespace Spring.Aop.Framework.DynamicProxy
Assert.AreEqual(1, nop1.Count);
Assert.AreEqual(1, nop2.Count);
// Will fail, after invoking Nop1
- try
+ try
{
proxied.Age = 26;
Assert.Fail("before advice should have ended chain");
}
- catch (ApplicationException ex)
+ catch (ApplicationException ex)
{
Assert.AreEqual(aex, ex);
}
@@ -2319,11 +2462,11 @@ namespace Spring.Aop.Framework.DynamicProxy
_exception = ex;
}
- public override void Before(MethodInfo method, object[] args, object target)
+ public override void Before(MethodInfo method, object[] args, object target)
{
- base.Before(method, args, target);
+ base.Before(method, args, target);
- if (method.Name.StartsWith("set_"))
+ if (method.Name.StartsWith("set_"))
throw _exception;
}
}
@@ -2333,7 +2476,7 @@ namespace Spring.Aop.Framework.DynamicProxy
#region AfterReturningAdvisorIsInvoked
[Test]
- public void AfterReturningAdvisorIsInvoked()
+ public void AfterReturningAdvisorIsInvoked()
{
SummingAfterAdvice aa = new SummingAfterAdvice();
IAdvisor matchesIntAdvisor = new ReturnsIntPointcutAdvisor(aa);
@@ -2440,14 +2583,14 @@ namespace Spring.Aop.Framework.DynamicProxy
{
Assert.AreEqual(ex, caught);
}
-
+
ex = new HttpException();
- try
+ try
{
proxied.EchoException(1, ex);
Assert.Fail("Should have thrown HttpException");
}
- catch (HttpException caught)
+ catch (HttpException caught)
{
Assert.AreEqual(ex, caught);
}
@@ -2486,19 +2629,19 @@ namespace Spring.Aop.Framework.DynamicProxy
Assert.AreEqual(0, th.GetCalls());
Exception ex = new Exception();
// Will be advised but doesn't match
- try
+ try
{
proxied.EchoException(1, ex);
Assert.Fail("Should have thrown Exception");
}
- catch (Exception caught)
+ catch (Exception caught)
{
Assert.AreEqual(ex, caught);
}
// Subclass of RemoteException
ex = new RemotingTimeoutException();
- try
+ try
{
proxied.EchoException(1, ex);
Assert.Fail("Should have thrown RemotingTimeoutException");
@@ -2563,7 +2706,7 @@ namespace Spring.Aop.Framework.DynamicProxy
#endregion
}
-#endregion
+ #endregion
#region Helper classes definitions
@@ -2619,6 +2762,59 @@ namespace Spring.Aop.Framework.DynamicProxy
}
}
+ public class DynamicTargetSource : ITargetSource
+ {
+ private object target;
+ private Type targetType;
+
+ public DynamicTargetSource(Type targetType, object target)
+ {
+ this.targetType = targetType;
+ this.target = target;
+ }
+
+ public object Target
+ {
+ get { return target; }
+ set { target = value; }
+ }
+
+ public Type TargetType
+ {
+ get { return targetType; }
+ set { targetType = value; }
+ }
+
+ public bool IsStatic
+ {
+ get { return false; }
+ }
+
+ public virtual object GetTarget()
+ {
+ return target;
+ }
+
+ public void ReleaseTarget(object target)
+ { }
+ }
+
+ public class DynamicInvocationTestInterceptor : IMethodInterceptor
+ {
+ public bool CallProceed = false;
+ public IMethodInvocation LastMethodInvocation;
+
+ public object Invoke(IMethodInvocation invocation)
+ {
+ LastMethodInvocation = invocation;
+ if (CallProceed)
+ {
+ return invocation.Proceed();
+ }
+ return null;
+ }
+ }
+
#endregion
}
}
diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs
index de17d2c9..31982a31 100644
--- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs
+++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CompositionAopProxyTests.cs
@@ -27,7 +27,10 @@ using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
+using AopAlliance.Intercept;
+using DotNetMock.Dynamic;
using NUnit.Framework;
+using Rhino.Mocks;
using Spring.Aop.Interceptor;
using Spring.Aop.Support;
using Spring.Objects;
diff --git a/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs
index 731210e8..2d4e952a 100644
--- a/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs
+++ b/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs
@@ -21,25 +21,29 @@
#region Imports
using System;
-
+using System.Reflection;
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Proxies;
using NUnit.Framework;
+using Spring.Objects;
#endregion
namespace Spring.Util
{
- ///
- /// Unit tests for the AssertUtils class.
- ///
- /// Rick Evans
- [TestFixture]
- public sealed class AssertUtilsTests
- {
+ ///
+ /// Unit tests for the AssertUtils class.
+ ///
+ /// Rick Evans
+ [TestFixture]
+ public sealed class AssertUtilsTests
+ {
[Test]
- [ExpectedException(typeof(ArgumentException),ExpectedMessage = "foo")]
+ [ExpectedException(typeof(ArgumentException), ExpectedMessage = "foo")]
public void IsTrueWithMesssage()
{
- AssertUtils.IsTrue(false,"foo");
+ AssertUtils.IsTrue(false, "foo");
}
[Test]
@@ -65,48 +69,48 @@ namespace Spring.Util
[ExpectedException(typeof(InvalidOperationException))]
public void StateTrue()
{
- AssertUtils.State(false,"foo");
+ AssertUtils.State(false, "foo");
}
- [Test]
- [ExpectedException(typeof(ArgumentNullException))]
- public void ArgumentNotNull ()
- {
- AssertUtils.ArgumentNotNull(null, "foo");
- }
-
- [Test]
+ [Test]
[ExpectedException(typeof(ArgumentNullException))]
- public void ArgumentNotNullWithMessage ()
- {
- AssertUtils.ArgumentNotNull(null, "foo", "Bang!");
- }
+ public void ArgumentNotNull()
+ {
+ AssertUtils.ArgumentNotNull(null, "foo");
+ }
- [Test]
- public void ArgumentHasTextWithValidText()
- {
- AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo");
- }
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void ArgumentNotNullWithMessage()
+ {
+ AssertUtils.ArgumentNotNull(null, "foo", "Bang!");
+ }
- [Test]
- public void ArgumentHasTextWithValidTextAndMessage()
- {
- AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo", "Bang!");
- }
+ [Test]
+ public void ArgumentHasTextWithValidText()
+ {
+ AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo");
+ }
- [Test]
- [ExpectedException(typeof(ArgumentNullException))]
- public void ArgumentHasText ()
- {
- AssertUtils.ArgumentHasText(null, "foo");
- }
+ [Test]
+ public void ArgumentHasTextWithValidTextAndMessage()
+ {
+ AssertUtils.ArgumentHasText("... and no-one's getting fat 'cept Mama Cas!", "foo", "Bang!");
+ }
- [Test]
- [ExpectedException(typeof(ArgumentNullException))]
- public void ArgumentHasTextWithMessage ()
- {
- AssertUtils.ArgumentHasText(null, "foo", "Bang!");
- }
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void ArgumentHasText()
+ {
+ AssertUtils.ArgumentHasText(null, "foo");
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void ArgumentHasTextWithMessage()
+ {
+ AssertUtils.ArgumentHasText(null, "foo", "Bang!");
+ }
[Test]
[ExpectedException(typeof(ArgumentNullException))]
@@ -174,5 +178,110 @@ namespace Spring.Util
{
AssertUtils.ArgumentHasElements(new object[] { new object(), new object(), new object() }, "foo");
}
+
+ [Test]
+ public void UnderstandsType()
+ {
+ MethodInfo getDescriptionMethod = typeof(ITestObject).GetMethod("GetDescription", new Type[0]);
+ MethodInfo understandsMethod = typeof(AssertUtils).GetMethod("Understands", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof (object), typeof(string), typeof (MethodBase)}, null);
+
+ // null target, any type
+ AssertNotUnderstandsType(null, "target", typeof(object), typeof(NotSupportedException), "Target 'target' is null.");
+ // any target, null type
+ AssertNotUnderstandsType(new object(), "target", null, typeof(ArgumentNullException), "Argument 'requiredType' cannot be null.");
+ }
+
+ [Test]
+ public void UnderstandsMethod()
+ {
+ MethodInfo getDescriptionMethod = typeof(ITestObject).GetMethod("GetDescription", new Type[0]);
+ MethodInfo understandsMethod = typeof(AssertUtils).GetMethod("Understands", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof (object), typeof(string), typeof (MethodBase)}, null);
+
+ // null target, static method
+ AssertUtils.Understands(null, "target", understandsMethod);
+ // null target, instance method
+ AssertNotUnderstandsMethod(null, "target", getDescriptionMethod, typeof(NotSupportedException), "Target 'target' is null and target method 'Spring.Objects.ITestObject.GetDescription' is not static.");
+ // compatible target, instance method
+ AssertUtils.Understands(new TestObject(), "target", getDescriptionMethod);
+ // incompatible target, instance method
+ AssertNotUnderstandsMethod(new object(), "target", getDescriptionMethod, typeof(NotSupportedException), "Target 'target' of type 'System.Object' does not support methods of 'Spring.Objects.ITestObject'.");
+ // compatible transparent proxy, instance method
+ object compatibleProxy = new TestProxy(new TestObject()).GetTransparentProxy();
+ AssertUtils.Understands(compatibleProxy, "compatibleProxy", getDescriptionMethod);
+ // incompatible transparent proxy, instance method
+ object incompatibleProxy = new TestProxy(new object()).GetTransparentProxy();
+ AssertNotUnderstandsMethod(incompatibleProxy, "incompatibleProxy", getDescriptionMethod, typeof(NotSupportedException), "Target 'incompatibleProxy' is a transparent proxy that does not support methods of 'Spring.Objects.ITestObject'.");
+ }
+
+ private void AssertNotUnderstandsType(object target, string targetName, Type requiredType, Type exceptionType, string partialMessage)
+ {
+ try
+ {
+ AssertUtils.Understands(target, targetName, requiredType);
+ Assert.Fail();
+ }
+ catch(Exception ex)
+ {
+ if (ex.GetType() != exceptionType)
+ {
+ Assert.Fail("Expected Exception of type {0}, but was {1}", exceptionType, ex.GetType());
+ }
+
+ if (-1 == ex.Message.IndexOf(partialMessage))
+ {
+ Assert.Fail("Expected Message '{0}', but got '{1}'", partialMessage, ex.Message);
+ }
+ }
+ }
+
+ private void AssertNotUnderstandsMethod(object target, string targetName, MethodBase method, Type exceptionType, string partialMessage)
+ {
+ try
+ {
+ AssertUtils.Understands(target, targetName, method);
+ Assert.Fail();
+ }
+ catch(Exception ex)
+ {
+ if (ex.GetType() != exceptionType)
+ {
+ Assert.Fail("Expected Exception of type {0}, but was {1}", exceptionType, ex.GetType());
+ }
+
+ if (-1 == ex.Message.IndexOf(partialMessage))
+ {
+ Assert.Fail("Expected Message '{0}', but got '{1}'", partialMessage, ex.Message);
+ }
+ }
+ }
+
+ private class TestProxy : RealProxy, IRemotingTypeInfo
+ {
+ private readonly object targetInstance;
+
+ public TestProxy(object targetInstance)
+ : base(typeof(MarshalByRefObject))
+ {
+ this.targetInstance = targetInstance;
+ }
+
+ public override IMessage Invoke(IMessage msg)
+ {
+ // return new ReturnMessage(result, null, 0, null, callMsg);
+ throw new NotSupportedException();
+ }
+
+ public bool CanCastTo(Type fromType, object o)
+ {
+ bool res = fromType.IsAssignableFrom(targetInstance.GetType());
+ return res;
+ }
+
+ public string TypeName
+ {
+ get { return targetInstance.GetType().AssemblyQualifiedName; }
+ set { throw new System.NotSupportedException(); }
+ }
+ }
}
}