diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs
index df4c751d..b4f6fec9 100644
--- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs
+++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs
@@ -330,9 +330,10 @@ namespace Spring.Aop.Framework.AutoProxy
#region InheritanceBasedAopTargetSource inner class definition
+ [Serializable]
private class InheritanceBasedAopTargetSource : ITargetSource
{
- private Type _targetType;
+ private readonly Type _targetType;
public InheritanceBasedAopTargetSource(Type targetType)
{
diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs
index b11d4d37..6abb8a1e 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AbstractRegularExpressionMethodPointcut.cs
@@ -94,17 +94,29 @@ namespace Spring.Aop.Support
protected AbstractRegularExpressionMethodPointcut(
SerializationInfo info, StreamingContext context)
{
- _patterns = (object[]) info.GetValue("Patterns", typeof(object[]));
- try
- {
- InitPatternRepresentation(_patterns);
- }
- catch (Exception ex)
- {
- throw new AspectException(
- "Failed to deserialize AOP regular expression pointcut: " + ex.Message);
- }
- }
+ _patterns = (object[]) info.GetValue("Patterns", typeof(object[]));
+ if (_patterns == null)
+ {
+ _patterns = ObjectUtils.EmptyObjects;
+ }
+ }
+
+ ///
+ /// Overridden to ensure proper initialization
+ ///
+ protected override void OnDeserialization(object sender)
+ {
+ base.OnDeserialization(sender);
+ try
+ {
+ InitPatternRepresentation(_patterns);
+ }
+ catch (Exception ex)
+ {
+ throw new AspectException(
+ "Failed to deserialize AOP regular expression pointcut: " + ex.Message);
+ }
+ }
#endregion
diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs
index 12940a80..df9f51d4 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchingPointcut.cs
@@ -29,6 +29,7 @@ namespace Spring.Aop.Support
///
/// Juergen Hoeller
/// Mark Pollack (.NET)
+ [Serializable]
public class AttributeMatchingPointcut : IPointcut
{
private readonly ITypeFilter typeFilter;
diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs
index 989ae74c..34cb8965 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMethodMatcher.cs
@@ -32,6 +32,7 @@ namespace Spring.Aop.Support
/// Juergen hoeller
/// Mark Pollack
///
+ [Serializable]
public class AttributeMethodMatcher : StaticMethodMatcher
{
private readonly Type attributeType;
diff --git a/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs
index 34ad8422..0d07dbee 100644
--- a/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/DynamicMethodMatcher.cs
@@ -32,7 +32,8 @@ namespace Spring.Aop.Support
/// care about arguments at runtime.
///
/// Rod Johnson
- /// Aleksandar Seovic (.NET)
+ /// Aleksandar Seovic (.NET)
+ [Serializable]
public abstract class DynamicMethodMatcher : IMethodMatcher
{
#region Constructor (s) / Destructor
diff --git a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs
index 58a16374..81b92042 100644
--- a/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/StaticMethodMatcher.cs
@@ -21,7 +21,8 @@
#region Imports
using System;
-using System.Reflection;
+using System.Reflection;
+using System.Runtime.Serialization;
#endregion
@@ -34,7 +35,7 @@ namespace Spring.Aop.Support
/// Rod Johnson
/// Aleksandar Seovic (.NET)
[Serializable]
- public abstract class StaticMethodMatcher : IMethodMatcher
+ public abstract class StaticMethodMatcher : IMethodMatcher, IDeserializationCallback
{
///
/// Is this dynamic?
@@ -97,6 +98,23 @@ namespace Spring.Aop.Support
///
/// if this this method matches statically.
///
- public abstract bool Matches(MethodInfo method, Type targetType);
+ public abstract bool Matches(MethodInfo method, Type targetType);
+
+
+ #region Serialization Support
+
+ void IDeserializationCallback.OnDeserialization(object sender)
+ {
+ OnDeserialization(sender);
+ }
+
+ ///
+ /// Override in case you need to initialized non-serialized fields on deserialization.
+ ///
+ protected virtual void OnDeserialization(object sender)
+ {
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs
index e2e35ee5..8a5f88ff 100644
--- a/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/UnionPointcut.cs
@@ -85,7 +85,8 @@ namespace Spring.Aop.Support
///
/// Internal method matcher class for union pointcut.
- ///
+ ///
+ [Serializable]
private sealed class PointcutUnionMethodMatcher : IMethodMatcher
{
private UnionPointcut _enclosingInstance;
diff --git a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs
index 55f5d21c..9159efb6 100644
--- a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs
@@ -18,6 +18,8 @@
#endregion
+using System;
+using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using AopAlliance.Intercept;
using Spring.Objects.Factory;
@@ -31,8 +33,9 @@ namespace Spring.Aspects
///
///
///
- /// Mark Pollack
- public abstract class AbstractExceptionHandlerAdvice : IMethodInterceptor, IInitializingObject
+ /// Mark Pollack
+ [Serializable]
+ public abstract class AbstractExceptionHandlerAdvice : IMethodInterceptor, IInitializingObject, IDeserializationCallback
{
///
/// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and subclass specific actions.
@@ -151,6 +154,22 @@ namespace Spring.Aspects
RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);
Regex reg = new Regex(regexString, options);
return reg.Match(adviceExpressionString);
+ }
+
+ #region Serialization
+
+ void IDeserializationCallback.OnDeserialization(object sender)
+ {
+ OnDeserialization(sender);
+ }
+
+ ///
+ /// Override in case you need to initialized non-serialized fields on deserialization.
+ ///
+ protected virtual void OnDeserialization(object sender)
+ {
}
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs
index 3785a7ee..975a78d4 100644
--- a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs
@@ -68,6 +68,7 @@ namespace Spring.Aspects.Exceptions
///
///
/// Mark Pollack
+ [Serializable]
public class ExceptionHandlerAdvice : AbstractExceptionHandlerAdvice
{
#region Fields
diff --git a/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs b/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs
index 24016876..c023034f 100644
--- a/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs
@@ -20,6 +20,7 @@
using System;
using System.Reflection;
+using System.Runtime.Serialization;
using AopAlliance.Intercept;
using Common.Logging;
using Spring.Aop.Framework;
@@ -32,25 +33,44 @@ namespace Spring.Aspects.Logging
///
///
///
- /// Mark Pollack
- public abstract class AbstractLoggingAdvice : IMethodInterceptor
+ /// Mark Pollack
+ [Serializable]
+ public abstract class AbstractLoggingAdvice : IMethodInterceptor, IDeserializationCallback
{
#region Fields
///
/// The default ILog instance used to write logging messages.
- ///
- protected ILog defaultLogger = LogManager.GetLogger(MethodInfo.GetCurrentMethod().DeclaringType);
+ ///
+ [NonSerialized]
+ protected ILog defaultLogger;
+
+ ///
+ /// The name of the logger instance to use for obtaining from .
+ ///
+ private string defaultLoggerName;
///
/// Indicates whether or not proxy type names should be hidden when using dynamic loggers.
///
private bool hideProxyTypeNames = false;
- #endregion
-
- #region Properties
-
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Creates a new advice instance using this advice type's name for logging by default.
+ ///
+ protected AbstractLoggingAdvice()
+ {
+ SetDefaultLogger(MethodBase.GetCurrentMethod().DeclaringType.FullName);
+ }
+
+ #endregion
+
+ #region Properties
+
///
/// Sets a value indicating whether to use a dynamic logger or static logger
///
@@ -68,8 +88,8 @@ namespace Spring.Aspects.Logging
public bool UseDynamicLogger
{
set
- {
- defaultLogger = (value ? null : LogManager.GetLogger(GetType()));
+ {
+ SetDefaultLogger(value ? null : this.GetType().FullName);
}
}
@@ -91,8 +111,8 @@ namespace Spring.Aspects.Logging
public string LoggerName
{
set
- {
- defaultLogger = LogManager.GetLogger(value);
+ {
+ SetDefaultLogger(value);
}
}
@@ -234,6 +254,29 @@ namespace Spring.Aspects.Logging
}
}
- #endregion
+ #endregion
+
+ ///
+ /// Sets the default logger to the given name.
+ ///
+ /// if null, the default logger is removed.
+ protected void SetDefaultLogger(string name)
+ {
+ defaultLogger = (name == null ? null : LogManager.GetLogger(name));
+ defaultLoggerName = name;
+ }
+
+ void IDeserializationCallback.OnDeserialization(object sender)
+ {
+ OnDeserialization(sender);
+ }
+
+ ///
+ /// Override in case you need to initialized non-serialized fields on deserialization.
+ ///
+ protected virtual void OnDeserialization(object sender)
+ {
+ SetDefaultLogger(this.defaultLoggerName);
+ }
}
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs b/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs
index 2135e1ce..22a0ddf2 100644
--- a/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs
@@ -32,7 +32,8 @@ namespace Spring.Aspects.Logging
///
///
///
- /// Mark Pollack
+ /// Mark Pollack
+ [Serializable]
public class SimpleLoggingAdvice : AbstractLoggingAdvice
{
#region Fields
diff --git a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
index b2ab7fd8..3d9b186a 100644
--- a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
@@ -37,15 +37,22 @@ namespace Spring.Aspects
///
///
///
- /// Mark Pollack
+ /// Mark Pollack
+ [Serializable]
public class RetryAdvice : AbstractExceptionHandlerAdvice
- {
+ {
+ private static readonly ILog log;
+ private static readonly TimeSpanConverter timeSpanConverter;
+
+ static RetryAdvice()
+ {
+ log = LogManager.GetLogger(typeof(RetryAdvice));
+ timeSpanConverter = new TimeSpanConverter();
+ }
+
#region Fields
- private static readonly ILog log = LogManager.GetLogger(typeof (RetryAdvice));
-
- private TimeSpanConverter timeSpanConverter = new TimeSpanConverter();
-
+ [NonSerialized]
private RetryExceptionHandler retryExceptionHandler;
private string retryExpression;
@@ -309,7 +316,18 @@ namespace Spring.Aspects
RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);
Regex reg = new Regex(regexString, options);
return reg.Match(actionExpressionString);
+ }
+
+ ///
+ /// Override in case you need to initialized non-serialized fields on deserialization.
+ ///
+ protected override void OnDeserialization(object sender)
+ {
+ base.OnDeserialization(sender);
+ if (retryExpression != null)
+ {
+ this.AfterPropertiesSet();
+ }
}
-
}
}
\ No newline at end of file
diff --git a/test/Spring/Spring.Aop.Tests/AopSerializationTests.cs b/test/Spring/Spring.Aop.Tests/AopSerializationTests.cs
new file mode 100644
index 00000000..f4ae778b
--- /dev/null
+++ b/test/Spring/Spring.Aop.Tests/AopSerializationTests.cs
@@ -0,0 +1,139 @@
+#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 System.Collections;
+using System.IO;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters;
+using System.Runtime.Serialization.Formatters.Binary;
+using AopAlliance.Aop;
+using NUnit.Framework;
+using Spring.Aop;
+using Spring.Aop.Framework;
+using Spring.Aop.Support;
+using Spring.Context;
+using Spring.Objects.Factory;
+
+namespace Spring
+{
+ ///
+ /// Ensure, that all framework implementations of IAdvice and IAdvisor are serializable
+ ///
+ /// Erich Eichinger
+ [TestFixture]
+ public class AopSerializationTests
+ {
+ public AopSerializationTests()
+ { }
+
+ [Test]
+ public void AllAopInfrastructureTypesAreSerializable()
+ {
+ ArrayList brokenTypes = new ArrayList();
+
+ foreach (Type t in GetTypesToTest())
+ {
+ if (!ExcludeTypeFromTest(t)
+ && IsAopInfrastructureType(t))
+ {
+ if (!CheckIsSerializable(t))
+ {
+ brokenTypes.Add(string.Format("{0} or one of its base classes are not marked as serializable\n", t.FullName));
+ continue;
+ }
+ if (t.IsAbstract) continue;
+
+ // perform a fast ser/deser check
+ try
+ {
+ object o = FormatterServices.GetSafeUninitializedObject(t);
+ o = SerializeAndDeserialize(o);
+ }
+ catch (SerializationException sex)
+ {
+ brokenTypes.Add(string.Format("{0}: {1}\n", t.FullName, sex.Message));
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(string.Format("WARN: {0}: {1}\n", t.FullName, ex));
+ }
+ }
+ }
+
+ Assert.IsEmpty(brokenTypes);
+ }
+
+ protected bool CheckIsSerializable(Type t)
+ {
+ if (t == typeof(object)) return true;
+
+ return (t.IsSerializable && CheckIsSerializable(t.BaseType));
+ }
+
+ protected virtual ICollection GetTypesToTest()
+ {
+ return GetAssemblyToTest().GetTypes();
+ // return new Type[] { typeof(DynamicMethodMatcherPointcutAdvisor) };
+ }
+
+ protected virtual Assembly GetAssemblyToTest()
+ {
+ return typeof(IAdvice).Assembly;
+ }
+
+ protected virtual bool ExcludeTypeFromTest(Type t)
+ {
+ return false //t.IsAbstract
+ || t.IsInterface
+ || typeof(IApplicationContextAware).IsAssignableFrom(t)
+ || typeof(IObjectFactoryAware).IsAssignableFrom(t)
+ ;
+ }
+
+ protected virtual bool IsAopInfrastructureType(Type t)
+ {
+ return typeof(IAdvisedSupportListener).IsAssignableFrom(t)
+ || typeof(ITargetSource).IsAssignableFrom(t)
+ || typeof(IAdvice).IsAssignableFrom(t)
+ || typeof(IAdvisor).IsAssignableFrom(t)
+ || typeof(IMethodMatcher).IsAssignableFrom(t)
+ || typeof(IPointcut).IsAssignableFrom(t);
+ }
+
+ private object SerializeAndDeserialize(object s)
+ {
+ // Serialize the session
+ using (Stream stream = new MemoryStream())
+ {
+ BinaryFormatter formatter = new BinaryFormatter();
+ formatter.AssemblyFormat = FormatterAssemblyStyle.Full;
+ formatter.TypeFormat = FormatterTypeStyle.TypesAlways;
+ formatter.Serialize(stream, s);
+
+ // Deserialize the session
+ stream.Position = 0;
+ object res = formatter.Deserialize(stream);
+ return res;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj
index 1a03e27a..3dce2ff2 100644
--- a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj
+++ b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj
@@ -106,6 +106,7 @@
Code
+