diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs
index 9e768e0e..410700e7 100644
--- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs
+++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/TypeNameAutoProxyCreator.cs
@@ -41,7 +41,14 @@ namespace Spring.Aop.Framework.AutoProxy
///
public string[] TypeNames
{
- get { return _typeNameFilter.TypeNamePatterns; }
+ get
+ {
+ if (_typeNameFilter != null)
+ {
+ return _typeNameFilter.TypeNamePatterns;
+ }
+ return null;
+ }
set
{
AssertUtils.ArgumentNotNull(value, "TypeNames");
@@ -55,8 +62,8 @@ namespace Spring.Aop.Framework.AutoProxy
///
/// Override this method to allow or reject proxying for the given object.
///
- /// the object's type
- /// the name of the object
+ /// the object's type
+ /// the name of the object
///
/// whether the given object shall be proxied.
protected override bool IsEligibleForProxying(Type targetType, string targetName)
diff --git a/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs b/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs
index eef97bdc..c2da3a68 100644
--- a/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs
+++ b/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs
@@ -1,724 +1,724 @@
-#region License
-
-/*
- * Copyright © 2002-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Collections;
-using System.Reflection;
-using System.Runtime.Remoting;
-using System.Runtime.Serialization;
-
-using Spring.Collections;
-using Spring.Core;
-using Spring.Core.TypeConversion;
-using Spring.Core.TypeResolution;
-using Spring.Util;
-using Spring.Reflection.Dynamic;
-
-#endregion
-
-namespace Spring.Expressions
-{
- ///
- /// Represents node that navigates to object's property or public field.
- ///
- /// Aleksandar Seovic
- [Serializable]
- public class PropertyOrFieldNode : BaseNode
- {
- //private static readonly Common.Logging.ILog Log = Common.Logging.LogManager.GetLogger(typeof(PropertyOrFieldNode));
-
- private const BindingFlags BINDING_FLAGS =
- BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static |
- BindingFlags.IgnoreCase;
-
- private string memberName;
- private IValueAccessor accessor;
-
- ///
- /// Create a new instance
- ///
- public PropertyOrFieldNode()
- {
- }
-
- ///
- /// Create a new instance from SerializationInfo
- ///
- protected PropertyOrFieldNode(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
- ///
- /// Initializes the node.
- ///
- /// The parent.
- private void InitializeNode(object context)
- {
- Type contextType = (context == null || context is Type ? context as Type : context.GetType());
-
- if (accessor == null || accessor.RequiresRefresh(contextType))
- {
- memberName = this.getText();
-
- // clear cached member info if context type has changed (for example, when ASP.NET page is recompiled)
- if (accessor != null && accessor.RequiresRefresh(contextType))
- {
- accessor = null;
- }
-
- // initialize this node if necessary
- if (contextType != null && accessor == null)
- {
- // try to initialize node as enum value first
- if (contextType.IsEnum)
- {
- try
- {
- accessor = new EnumValueAccessor(Enum.Parse(contextType, memberName, true));
- }
- catch (ArgumentException)
- {
- // ArgumentException will be thrown if specified member name is not a valid
- // enum value for the context type. We should just ignore it and continue processing,
- // because the specified member could be a property of a Type class (i.e. EnumType.FullName)
- }
- }
-
- // then try to initialize node as property or field value
- if (accessor == null)
- {
- // check the context type first
- accessor = GetPropertyOrFieldAccessor(contextType, memberName, BINDING_FLAGS);
-
- // if not found, probe the Type type
- if (accessor == null && context is Type)
- {
- accessor = GetPropertyOrFieldAccessor(typeof(Type), memberName, BINDING_FLAGS);
- }
- }
- }
-
- // if there is still no match, try to initialize node as type accessor
- if (accessor == null)
- {
- try
- {
- accessor = new TypeValueAccessor(TypeResolutionUtils.ResolveType(memberName));
- }
- catch (TypeLoadException)
- {
- if (context == null)
- {
- throw new NullValueInNestedPathException("Cannot initialize property or field node '" +
- memberName +
- "' because the specified context is null.");
- }
- else
- {
- throw new InvalidPropertyException(contextType, memberName,
- "'" + memberName +
- "' node cannot be resolved for the specified context [" +
- context + "].");
- }
- }
- }
- }
- }
-
- ///
- /// Attempts to resolve property or field.
- ///
- ///
- /// Type to search for a property or a field.
- ///
- ///
- /// Property or field name.
- ///
- ///
- /// Binding flags to use.
- ///
- ///
- /// Resolved property or field accessor, or null
- /// if specified cannot be resolved.
- ///
- private static IValueAccessor GetPropertyOrFieldAccessor(Type contextType, string memberName, BindingFlags bindingFlags)
- {
- try
- {
- PropertyInfo pi = contextType.GetProperty(memberName, bindingFlags);
- if (pi == null)
- {
- FieldInfo fi = contextType.GetField(memberName, bindingFlags);
- if (fi != null)
- {
- return new FieldValueAccessor(fi);
- }
- }
- else
- {
- return new PropertyValueAccessor(pi);
- }
- }
- catch (AmbiguousMatchException)
- {
- PropertyInfo pi = null;
-
- // search type hierarchy
- while (contextType != typeof(object))
- {
- pi = contextType.GetProperty(memberName, bindingFlags | BindingFlags.DeclaredOnly);
- if (pi == null)
- {
- FieldInfo fi = contextType.GetField(memberName, bindingFlags | BindingFlags.DeclaredOnly);
- if (fi != null)
- {
- return new FieldValueAccessor(fi);
- }
- }
- else
- {
- return new PropertyValueAccessor(pi);
- }
- contextType = contextType.BaseType;
- }
- }
-
- return null;
- }
-
- ///
- /// Returns node's value for the given context.
- ///
- /// Context to evaluate expressions against.
- /// Current expression evaluation context.
- /// Node's value.
- protected override object Get(object context, EvaluationContext evalContext)
- {
- lock (this)
- {
- InitializeNode(context);
-
- if (context == null && accessor.RequiresContext)
- {
- throw new NullValueInNestedPathException(
- "Cannot retrieve the value of a field or property '" + this.memberName
- + "', because context for its resolution is null.");
- }
- if (IsProperty || IsField)
- {
- return GetPropertyOrFieldValue(context, evalContext);
- }
- else
- {
- return accessor.Get(context);
- }
- }
- }
-
- ///
- /// Sets node's value for the given context.
- ///
- /// Context to evaluate expressions against.
- /// Current expression evaluation context.
- /// New value for this node.
- protected override void Set(object context, EvaluationContext evalContext, object newValue)
- {
- lock (this)
- {
- InitializeNode(context);
-
- if (context == null && accessor.RequiresContext)
- {
- throw new NullValueInNestedPathException(
- "Cannot set the value of a field or property '" + this.memberName
- + "', because context for its resolution is null.");
- }
- if (IsProperty || IsField)
- {
- SetPropertyOrFieldValue(context, evalContext, newValue);
- }
- else
- {
- accessor.Set(context, newValue);
- }
- }
- }
-
- ///
- /// Gets a value indicating whether this node represents a property.
- ///
- ///
- /// true if this node is a property; otherwise, false.
- ///
- private bool IsProperty
- {
- get { return accessor is PropertyValueAccessor; }
- }
-
- ///
- /// Gets a value indicating whether this node represents a field.
- ///
- ///
- /// true if this node is a field; otherwise, false.
- ///
- private bool IsField
- {
- get { return accessor is FieldValueAccessor; }
- }
-
- ///
- /// Retrieves property or field value.
- ///
- /// Context to evaluate expressions against.
- /// Current expression evaluation context.
- /// Property or field value.
- private object GetPropertyOrFieldValue(object context, EvaluationContext evalContext)
- {
- try
- {
- return accessor.Get(context);
- }
- catch (InvalidOperationException)
- {
- throw new NotReadablePropertyException(evalContext.RootContextType, this.memberName);
- }
- catch (TargetInvocationException e)
- {
- throw new InvalidPropertyException(evalContext.RootContextType, this.memberName,
- "Getter for property '" + this.memberName + "' threw an exception.",
- e);
- }
- catch (UnauthorizedAccessException e)
- {
- throw new InvalidPropertyException(evalContext.RootContextType, this.memberName,
- "Illegal attempt to get value for the property '" + this.memberName +
- "'.", e);
- }
- }
-
- ///
- /// Sets property value, doing any type conversions that are necessary along the way.
- ///
- /// Context to evaluate expressions against.
- /// Current expression evaluation context.
- /// New value for this node.
- private void SetPropertyOrFieldValue(object context, EvaluationContext evalContext, object newValue)
- {
- bool isWriteable = accessor.IsWriteable;
- Type targetType = accessor.TargetType;
-
- try
- {
- if (!isWriteable)
- {
- if (!AddToCollections(context, evalContext, newValue))
- {
- throw new NotWritablePropertyException(
- "Can't change the value of the read-only property or field '" + this.memberName + "'.");
- }
- }
- else if (targetType.IsPrimitive && (newValue == null || String.Empty.Equals(newValue)))
- {
- throw new ArgumentException("Invalid value [" + newValue + "] for property or field '" +
- this.memberName + "' of primitive type ["
- + targetType + "]");
+#region License
+
+/*
+ * Copyright © 2002-2005 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Runtime.Remoting;
+using System.Runtime.Serialization;
+
+using Spring.Collections;
+using Spring.Core;
+using Spring.Core.TypeConversion;
+using Spring.Core.TypeResolution;
+using Spring.Util;
+using Spring.Reflection.Dynamic;
+
+#endregion
+
+namespace Spring.Expressions
+{
+ ///
+ /// Represents node that navigates to object's property or public field.
+ ///
+ /// Aleksandar Seovic
+ [Serializable]
+ public class PropertyOrFieldNode : BaseNode
+ {
+ //private static readonly Common.Logging.ILog Log = Common.Logging.LogManager.GetLogger(typeof(PropertyOrFieldNode));
+
+ private const BindingFlags BINDING_FLAGS =
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static |
+ BindingFlags.IgnoreCase;
+
+ private string memberName;
+ private IValueAccessor accessor;
+
+ ///
+ /// Create a new instance
+ ///
+ public PropertyOrFieldNode()
+ {
+ }
+
+ ///
+ /// Create a new instance from SerializationInfo
+ ///
+ protected PropertyOrFieldNode(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+
+ ///
+ /// Initializes the node.
+ ///
+ /// The parent.
+ private void InitializeNode(object context)
+ {
+ Type contextType = (context == null || context is Type ? context as Type : context.GetType());
+
+ if (accessor == null || accessor.RequiresRefresh(contextType))
+ {
+ memberName = this.getText();
+
+ // clear cached member info if context type has changed (for example, when ASP.NET page is recompiled)
+ if (accessor != null && accessor.RequiresRefresh(contextType))
+ {
+ accessor = null;
}
- else if (newValue == null || ObjectUtils.IsAssignable(targetType, newValue)) // targetType.IsAssignableFrom(newValue.GetType())
- {
- SetPropertyOrFieldValueInternal(context, newValue);
- }
- else if (!RemotingServices.IsTransparentProxy(newValue) &&
- (newValue is IList || newValue is IDictionary || newValue is ISet))
- {
- if (!AddToCollections(context, evalContext, newValue))
- {
- object tmpValue =
- TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName);
- SetPropertyOrFieldValueInternal(context, tmpValue);
- }
- }
- else
- {
- object tmpValue = TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName);
- SetPropertyOrFieldValueInternal(context, tmpValue);
- }
- }
- catch (TargetInvocationException ex)
- {
- PropertyChangeEventArgs propertyChangeEvent =
- new PropertyChangeEventArgs(this.memberName, null, newValue);
- if (ex.GetBaseException() is InvalidCastException)
- {
- throw new TypeMismatchException(propertyChangeEvent, targetType, ex.GetBaseException());
- }
- else
- {
- throw new MethodInvocationException(ex.GetBaseException(), propertyChangeEvent);
- }
- }
- catch (UnauthorizedAccessException ex)
- {
- throw new FatalReflectionException("Illegal attempt to set property '" + this.memberName + "'", ex);
- }
- catch (NotWritablePropertyException)
- {
- throw;
- }
- catch (NotReadablePropertyException)
- {
- throw;
- }
- catch (ArgumentException ex)
- {
- PropertyChangeEventArgs propertyChangeEvent =
- new PropertyChangeEventArgs(this.memberName, null, newValue);
- throw new TypeMismatchException(propertyChangeEvent, targetType, ex);
- }
- }
-
- ///
- /// Sets property or field value using either dynamic or standard reflection.
- ///
- /// Object to evaluate node against.
- /// New value for this node, converted to appropriate type.
- private void SetPropertyOrFieldValueInternal(object context, object newValue)
- {
- accessor.Set(context, newValue);
- }
-
- ///
- /// In the case of read only collections or custom collections that are not assignable from
- /// IList, try to add to the collection.
- ///
- /// Context to evaluate expressions against.
- /// Current expression evaluation context.
- /// New value for this node.
- /// true if was able add to IList, IDictionary, or ISet
- private bool AddToCollections(object context, EvaluationContext evalContext, object newValue)
- {
- // short-circuit if accessor is not readable
- if (!this.accessor.IsReadable)
- {
- return false;
- }
-
- bool added = false;
-
- // try adding values if property is a list...
- if (newValue is IList && !RemotingServices.IsTransparentProxy(newValue))
- {
- IList currentValue = (IList)Get(context, evalContext);
- if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly)
- {
- foreach (object el in (IList)newValue)
- {
- currentValue.Add(el);
- }
- added = true;
- }
- }
- // try adding values if property is a dictionary...
- else if (newValue is IDictionary && !RemotingServices.IsTransparentProxy(newValue))
- {
- IDictionary currentValue = (IDictionary)Get(context, evalContext);
- if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly)
- {
- foreach (DictionaryEntry entry in (IDictionary)newValue)
- {
- currentValue[entry.Key] = entry.Value;
- }
- added = true;
- }
- }
- // try adding values if property is a set...
- else if (newValue is ISet && !RemotingServices.IsTransparentProxy(newValue))
- {
- ISet currentValue = (ISet)Get(context, evalContext);
- if (currentValue != null)
- {
- currentValue.AddAll((ICollection)newValue);
- added = true;
- }
- }
- return added;
- }
-
- ///
- /// Utility method that is needed by ObjectWrapper and AbstractAutowireCapableObjectFactory.
- /// We try as hard as we can, but there are instances when we won't be able to obtain PropertyInfo...
- ///
- /// Context to resolve property against.
- /// PropertyInfo for this node.
- internal MemberInfo GetMemberInfo(object context)
- {
- lock (this)
- {
- InitializeNode(context);
- }
- return accessor.MemberInfo;
-
- //if (IsProperty)
- //{
- // return (((PropertyValueAccessor) accessor).MemberInfo);
- //}
- //else
- //{
- // throw new FatalObjectException(
- // "Cannot obtain PropertyInfo from an expression that does not resolve to a property.");
- //}
- }
-
- #region IValueAccessor interface
-
- private interface IValueAccessor
- {
- object Get(object context);
- void Set(object context, object value);
-
- bool IsReadable { get; }
- bool IsWriteable { get; }
- bool RequiresContext { get; }
- Type TargetType { get; }
- MemberInfo MemberInfo { get; }
- bool RequiresRefresh(Type contextType);
- }
-
- #endregion
-
- #region BaseValueAccessor implementation
-
- private abstract class BaseValueAccessor : IValueAccessor
- {
- public abstract object Get(object context);
-
- public abstract void Set(object context, object value);
-
- public virtual bool IsReadable
- {
- get { return true; }
- }
-
- public virtual bool IsWriteable
- {
- get { return false; }
- }
-
- public virtual bool RequiresContext
- {
- get { return false; }
- }
-
- public virtual Type TargetType
- {
- get { throw new NotSupportedException(); }
- }
-
- public virtual MemberInfo MemberInfo
- {
- get { throw new NotSupportedException(); }
- }
-
- public virtual bool RequiresRefresh(Type contextType)
- {
- return false;
- }
- }
-
- #endregion
-
- #region PropertyValueAccessor implementation
-
- private class PropertyValueAccessor : BaseValueAccessor
- {
- private SafeProperty property;
- private string name;
- private bool isReadable;
- private bool isWriteable;
- private Type targetType;
- private Type contextType;
-
- public PropertyValueAccessor(PropertyInfo propertyInfo)
- {
- this.name = propertyInfo.Name;
- this.isReadable = propertyInfo.CanRead;
- this.isWriteable = propertyInfo.CanWrite;
- this.targetType = propertyInfo.PropertyType;
- this.contextType = propertyInfo.DeclaringType;
- this.property = new SafeProperty(propertyInfo);
- }
-
- public override object Get(object context)
- {
- if (!isReadable)
- {
- throw new NotReadablePropertyException("Cannot get a non-readable property [" + name + "]");
- }
- return property.GetValue(context);
- }
-
- public override void Set(object context, object value)
- {
- if (!isWriteable)
- {
- throw new NotWritablePropertyException("Cannot set a read-only property [" + name + "]");
- }
- property.SetValue(context, value);
- }
-
- public override bool IsReadable
- {
- get { return isReadable; }
- }
-
- public override bool IsWriteable
- {
- get { return isWriteable; }
- }
-
- public override bool RequiresContext
- {
- get { return true; }
- }
-
- public override Type TargetType
- {
- get { return targetType; }
- }
-
- public override MemberInfo MemberInfo
- {
- get { return property.PropertyInfo; }
- }
-
- public override bool RequiresRefresh(Type contextType)
- {
- return this.contextType != contextType;
- }
- }
-
- #endregion
-
- #region FieldValueAccessor implementation
-
- private class FieldValueAccessor : BaseValueAccessor
- {
- private SafeField field;
- private bool isWriteable;
- private Type targetType;
- private Type contextType;
-
- public FieldValueAccessor(FieldInfo fieldInfo)
- {
- this.field = new SafeField(fieldInfo);
- this.isWriteable = !(fieldInfo.IsInitOnly || fieldInfo.IsLiteral);
- this.targetType = fieldInfo.FieldType;
- this.contextType = fieldInfo.DeclaringType;
- }
-
- public override object Get(object context)
- {
- return field.GetValue(context);
- }
-
- public override void Set(object context, object value)
- {
- field.SetValue(context, value);
- }
-
- public override bool IsWriteable
- {
- get { return isWriteable; }
- }
-
- public override bool RequiresContext
- {
- get { return true; }
- }
-
- public override Type TargetType
- {
- get { return targetType; }
- }
-
- public override MemberInfo MemberInfo
- {
- get { return field.FieldInfo; }
- }
-
- public override bool RequiresRefresh(Type contextType)
- {
- return this.contextType != contextType;
- }
- }
-
- #endregion
-
- #region EnumValueAccessor implementation
-
- private class EnumValueAccessor : BaseValueAccessor
- {
- private object enumValue;
-
- public EnumValueAccessor(object enumValue)
- {
- this.enumValue = enumValue;
- }
-
- public override object Get(object context)
- {
- return enumValue;
- }
-
- public override void Set(object context, object value)
- {
- throw new NotSupportedException("Cannot set the value of an enum.");
- }
- }
-
- #endregion
-
- #region TypeValueAccessor implementation
-
- private class TypeValueAccessor : BaseValueAccessor
- {
- private Type type;
-
- public TypeValueAccessor(Type type)
- {
- this.type = type;
- }
-
- public override object Get(object context)
- {
- return type;
- }
-
- public override void Set(object context, object value)
- {
- throw new NotSupportedException("Cannot set the value of a type.");
- }
- }
-
- #endregion
- }
+
+ // initialize this node if necessary
+ if (contextType != null && accessor == null)
+ {
+ // try to initialize node as enum value first
+ if (contextType.IsEnum)
+ {
+ try
+ {
+ accessor = new EnumValueAccessor(Enum.Parse(contextType, memberName, true));
+ }
+ catch (ArgumentException)
+ {
+ // ArgumentException will be thrown if specified member name is not a valid
+ // enum value for the context type. We should just ignore it and continue processing,
+ // because the specified member could be a property of a Type class (i.e. EnumType.FullName)
+ }
+ }
+
+ // then try to initialize node as property or field value
+ if (accessor == null)
+ {
+ // check the context type first
+ accessor = GetPropertyOrFieldAccessor(contextType, memberName, BINDING_FLAGS);
+
+ // if not found, probe the Type type
+ if (accessor == null && context is Type)
+ {
+ accessor = GetPropertyOrFieldAccessor(typeof(Type), memberName, BINDING_FLAGS);
+ }
+ }
+ }
+
+ // if there is still no match, try to initialize node as type accessor
+ if (accessor == null)
+ {
+ try
+ {
+ accessor = new TypeValueAccessor(TypeResolutionUtils.ResolveType(memberName));
+ }
+ catch (TypeLoadException)
+ {
+ if (context == null)
+ {
+ throw new NullValueInNestedPathException("Cannot initialize property or field node '" +
+ memberName +
+ "' because the specified context is null.");
+ }
+ else
+ {
+ throw new InvalidPropertyException(contextType, memberName,
+ "'" + memberName +
+ "' node cannot be resolved for the specified context [" +
+ context + "].");
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Attempts to resolve property or field.
+ ///
+ ///
+ /// Type to search for a property or a field.
+ ///
+ ///
+ /// Property or field name.
+ ///
+ ///
+ /// Binding flags to use.
+ ///
+ ///
+ /// Resolved property or field accessor, or null
+ /// if specified cannot be resolved.
+ ///
+ private static IValueAccessor GetPropertyOrFieldAccessor(Type contextType, string memberName, BindingFlags bindingFlags)
+ {
+ try
+ {
+ PropertyInfo pi = contextType.GetProperty(memberName, bindingFlags);
+ if (pi == null)
+ {
+ FieldInfo fi = contextType.GetField(memberName, bindingFlags);
+ if (fi != null)
+ {
+ return new FieldValueAccessor(fi);
+ }
+ }
+ else
+ {
+ return new PropertyValueAccessor(pi);
+ }
+ }
+ catch (AmbiguousMatchException)
+ {
+ PropertyInfo pi = null;
+
+ // search type hierarchy
+ while (contextType != typeof(object))
+ {
+ pi = contextType.GetProperty(memberName, bindingFlags | BindingFlags.DeclaredOnly);
+ if (pi == null)
+ {
+ FieldInfo fi = contextType.GetField(memberName, bindingFlags | BindingFlags.DeclaredOnly);
+ if (fi != null)
+ {
+ return new FieldValueAccessor(fi);
+ }
+ }
+ else
+ {
+ return new PropertyValueAccessor(pi);
+ }
+ contextType = contextType.BaseType;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Returns node's value for the given context.
+ ///
+ /// Context to evaluate expressions against.
+ /// Current expression evaluation context.
+ /// Node's value.
+ protected override object Get(object context, EvaluationContext evalContext)
+ {
+ lock (this)
+ {
+ InitializeNode(context);
+
+ if (context == null && accessor.RequiresContext)
+ {
+ throw new NullValueInNestedPathException(
+ "Cannot retrieve the value of a field or property '" + this.memberName
+ + "', because context for its resolution is null.");
+ }
+ if (IsProperty || IsField)
+ {
+ return GetPropertyOrFieldValue(context, evalContext);
+ }
+ else
+ {
+ return accessor.Get(context);
+ }
+ }
+ }
+
+ ///
+ /// Sets node's value for the given context.
+ ///
+ /// Context to evaluate expressions against.
+ /// Current expression evaluation context.
+ /// New value for this node.
+ protected override void Set(object context, EvaluationContext evalContext, object newValue)
+ {
+ lock (this)
+ {
+ InitializeNode(context);
+
+ if (context == null && accessor.RequiresContext)
+ {
+ throw new NullValueInNestedPathException(
+ "Cannot set the value of a field or property '" + this.memberName
+ + "', because context for its resolution is null.");
+ }
+ if (IsProperty || IsField)
+ {
+ SetPropertyOrFieldValue(context, evalContext, newValue);
+ }
+ else
+ {
+ accessor.Set(context, newValue);
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this node represents a property.
+ ///
+ ///
+ /// true if this node is a property; otherwise, false.
+ ///
+ private bool IsProperty
+ {
+ get { return accessor is PropertyValueAccessor; }
+ }
+
+ ///
+ /// Gets a value indicating whether this node represents a field.
+ ///
+ ///
+ /// true if this node is a field; otherwise, false.
+ ///
+ private bool IsField
+ {
+ get { return accessor is FieldValueAccessor; }
+ }
+
+ ///
+ /// Retrieves property or field value.
+ ///
+ /// Context to evaluate expressions against.
+ /// Current expression evaluation context.
+ /// Property or field value.
+ private object GetPropertyOrFieldValue(object context, EvaluationContext evalContext)
+ {
+ try
+ {
+ return accessor.Get(context);
+ }
+ catch (InvalidOperationException)
+ {
+ throw new NotReadablePropertyException(evalContext.RootContextType, this.memberName);
+ }
+ catch (TargetInvocationException e)
+ {
+ throw new InvalidPropertyException(evalContext.RootContextType, this.memberName,
+ "Getter for property '" + this.memberName + "' threw an exception.",
+ e);
+ }
+ catch (UnauthorizedAccessException e)
+ {
+ throw new InvalidPropertyException(evalContext.RootContextType, this.memberName,
+ "Illegal attempt to get value for the property '" + this.memberName +
+ "'.", e);
+ }
+ }
+
+ ///
+ /// Sets property value, doing any type conversions that are necessary along the way.
+ ///
+ /// Context to evaluate expressions against.
+ /// Current expression evaluation context.
+ /// New value for this node.
+ private void SetPropertyOrFieldValue(object context, EvaluationContext evalContext, object newValue)
+ {
+ bool isWriteable = accessor.IsWriteable;
+ Type targetType = accessor.TargetType;
+
+ try
+ {
+ if (!isWriteable)
+ {
+ if (!AddToCollections(context, evalContext, newValue))
+ {
+ throw new NotWritablePropertyException(
+ "Can't change the value of the read-only property or field '" + this.memberName + "'.");
+ }
+ }
+ else if (targetType.IsPrimitive && (newValue == null || String.Empty.Equals(newValue)))
+ {
+ throw new ArgumentException("Invalid value [" + newValue + "] for property or field '" +
+ this.memberName + "' of primitive type ["
+ + targetType + "]");
+ }
+ else if (newValue == null || ObjectUtils.IsAssignable(targetType, newValue)) // targetType.IsAssignableFrom(newValue.GetType())
+ {
+ SetPropertyOrFieldValueInternal(context, newValue);
+ }
+ else if (!RemotingServices.IsTransparentProxy(newValue) &&
+ (newValue is IList || newValue is IDictionary || newValue is ISet))
+ {
+ if (!AddToCollections(context, evalContext, newValue))
+ {
+ object tmpValue =
+ TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName);
+ SetPropertyOrFieldValueInternal(context, tmpValue);
+ }
+ }
+ else
+ {
+ object tmpValue = TypeConversionUtils.ConvertValueIfNecessary(targetType, newValue, this.memberName);
+ SetPropertyOrFieldValueInternal(context, tmpValue);
+ }
+ }
+ catch (TargetInvocationException ex)
+ {
+ PropertyChangeEventArgs propertyChangeEvent =
+ new PropertyChangeEventArgs(this.memberName, null, newValue);
+ if (ex.GetBaseException() is InvalidCastException)
+ {
+ throw new TypeMismatchException(propertyChangeEvent, targetType, ex.GetBaseException());
+ }
+ else
+ {
+ throw new MethodInvocationException(ex.GetBaseException(), propertyChangeEvent);
+ }
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ throw new FatalReflectionException("Illegal attempt to set property '" + this.memberName + "'", ex);
+ }
+ catch (NotWritablePropertyException)
+ {
+ throw;
+ }
+ catch (NotReadablePropertyException)
+ {
+ throw;
+ }
+ catch (ArgumentException ex)
+ {
+ PropertyChangeEventArgs propertyChangeEvent =
+ new PropertyChangeEventArgs(this.memberName, null, newValue);
+ throw new TypeMismatchException(propertyChangeEvent, targetType, ex);
+ }
+ }
+
+ ///
+ /// Sets property or field value using either dynamic or standard reflection.
+ ///
+ /// Object to evaluate node against.
+ /// New value for this node, converted to appropriate type.
+ private void SetPropertyOrFieldValueInternal(object context, object newValue)
+ {
+ accessor.Set(context, newValue);
+ }
+
+ ///
+ /// In the case of read only collections or custom collections that are not assignable from
+ /// IList, try to add to the collection.
+ ///
+ /// Context to evaluate expressions against.
+ /// Current expression evaluation context.
+ /// New value for this node.
+ /// true if was able add to IList, IDictionary, or ISet
+ private bool AddToCollections(object context, EvaluationContext evalContext, object newValue)
+ {
+ // short-circuit if accessor is not readable or if we have an array
+ if (!this.accessor.IsReadable || this.accessor.TargetType.IsArray)
+ {
+ return false;
+ }
+
+ bool added = false;
+
+ // try adding values if property is a list...
+ if (newValue is IList && !RemotingServices.IsTransparentProxy(newValue))
+ {
+ IList currentValue = (IList)Get(context, evalContext);
+ if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly)
+ {
+ foreach (object el in (IList)newValue)
+ {
+ currentValue.Add(el);
+ }
+ added = true;
+ }
+ }
+ // try adding values if property is a dictionary...
+ else if (newValue is IDictionary && !RemotingServices.IsTransparentProxy(newValue))
+ {
+ IDictionary currentValue = (IDictionary)Get(context, evalContext);
+ if (currentValue != null && !currentValue.IsFixedSize && !currentValue.IsReadOnly)
+ {
+ foreach (DictionaryEntry entry in (IDictionary)newValue)
+ {
+ currentValue[entry.Key] = entry.Value;
+ }
+ added = true;
+ }
+ }
+ // try adding values if property is a set...
+ else if (newValue is ISet && !RemotingServices.IsTransparentProxy(newValue))
+ {
+ ISet currentValue = (ISet)Get(context, evalContext);
+ if (currentValue != null)
+ {
+ currentValue.AddAll((ICollection)newValue);
+ added = true;
+ }
+ }
+ return added;
+ }
+
+ ///
+ /// Utility method that is needed by ObjectWrapper and AbstractAutowireCapableObjectFactory.
+ /// We try as hard as we can, but there are instances when we won't be able to obtain PropertyInfo...
+ ///
+ /// Context to resolve property against.
+ /// PropertyInfo for this node.
+ internal MemberInfo GetMemberInfo(object context)
+ {
+ lock (this)
+ {
+ InitializeNode(context);
+ }
+ return accessor.MemberInfo;
+
+ //if (IsProperty)
+ //{
+ // return (((PropertyValueAccessor) accessor).MemberInfo);
+ //}
+ //else
+ //{
+ // throw new FatalObjectException(
+ // "Cannot obtain PropertyInfo from an expression that does not resolve to a property.");
+ //}
+ }
+
+ #region IValueAccessor interface
+
+ private interface IValueAccessor
+ {
+ object Get(object context);
+ void Set(object context, object value);
+
+ bool IsReadable { get; }
+ bool IsWriteable { get; }
+ bool RequiresContext { get; }
+ Type TargetType { get; }
+ MemberInfo MemberInfo { get; }
+ bool RequiresRefresh(Type contextType);
+ }
+
+ #endregion
+
+ #region BaseValueAccessor implementation
+
+ private abstract class BaseValueAccessor : IValueAccessor
+ {
+ public abstract object Get(object context);
+
+ public abstract void Set(object context, object value);
+
+ public virtual bool IsReadable
+ {
+ get { return true; }
+ }
+
+ public virtual bool IsWriteable
+ {
+ get { return false; }
+ }
+
+ public virtual bool RequiresContext
+ {
+ get { return false; }
+ }
+
+ public virtual Type TargetType
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public virtual MemberInfo MemberInfo
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public virtual bool RequiresRefresh(Type contextType)
+ {
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region PropertyValueAccessor implementation
+
+ private class PropertyValueAccessor : BaseValueAccessor
+ {
+ private SafeProperty property;
+ private string name;
+ private bool isReadable;
+ private bool isWriteable;
+ private Type targetType;
+ private Type contextType;
+
+ public PropertyValueAccessor(PropertyInfo propertyInfo)
+ {
+ this.name = propertyInfo.Name;
+ this.isReadable = propertyInfo.CanRead;
+ this.isWriteable = propertyInfo.CanWrite;
+ this.targetType = propertyInfo.PropertyType;
+ this.contextType = propertyInfo.DeclaringType;
+ this.property = new SafeProperty(propertyInfo);
+ }
+
+ public override object Get(object context)
+ {
+ if (!isReadable)
+ {
+ throw new NotReadablePropertyException("Cannot get a non-readable property [" + name + "]");
+ }
+ return property.GetValue(context);
+ }
+
+ public override void Set(object context, object value)
+ {
+ if (!isWriteable)
+ {
+ throw new NotWritablePropertyException("Cannot set a read-only property [" + name + "]");
+ }
+ property.SetValue(context, value);
+ }
+
+ public override bool IsReadable
+ {
+ get { return isReadable; }
+ }
+
+ public override bool IsWriteable
+ {
+ get { return isWriteable; }
+ }
+
+ public override bool RequiresContext
+ {
+ get { return true; }
+ }
+
+ public override Type TargetType
+ {
+ get { return targetType; }
+ }
+
+ public override MemberInfo MemberInfo
+ {
+ get { return property.PropertyInfo; }
+ }
+
+ public override bool RequiresRefresh(Type contextType)
+ {
+ return this.contextType != contextType;
+ }
+ }
+
+ #endregion
+
+ #region FieldValueAccessor implementation
+
+ private class FieldValueAccessor : BaseValueAccessor
+ {
+ private SafeField field;
+ private bool isWriteable;
+ private Type targetType;
+ private Type contextType;
+
+ public FieldValueAccessor(FieldInfo fieldInfo)
+ {
+ this.field = new SafeField(fieldInfo);
+ this.isWriteable = !(fieldInfo.IsInitOnly || fieldInfo.IsLiteral);
+ this.targetType = fieldInfo.FieldType;
+ this.contextType = fieldInfo.DeclaringType;
+ }
+
+ public override object Get(object context)
+ {
+ return field.GetValue(context);
+ }
+
+ public override void Set(object context, object value)
+ {
+ field.SetValue(context, value);
+ }
+
+ public override bool IsWriteable
+ {
+ get { return isWriteable; }
+ }
+
+ public override bool RequiresContext
+ {
+ get { return true; }
+ }
+
+ public override Type TargetType
+ {
+ get { return targetType; }
+ }
+
+ public override MemberInfo MemberInfo
+ {
+ get { return field.FieldInfo; }
+ }
+
+ public override bool RequiresRefresh(Type contextType)
+ {
+ return this.contextType != contextType;
+ }
+ }
+
+ #endregion
+
+ #region EnumValueAccessor implementation
+
+ private class EnumValueAccessor : BaseValueAccessor
+ {
+ private object enumValue;
+
+ public EnumValueAccessor(object enumValue)
+ {
+ this.enumValue = enumValue;
+ }
+
+ public override object Get(object context)
+ {
+ return enumValue;
+ }
+
+ public override void Set(object context, object value)
+ {
+ throw new NotSupportedException("Cannot set the value of an enum.");
+ }
+ }
+
+ #endregion
+
+ #region TypeValueAccessor implementation
+
+ private class TypeValueAccessor : BaseValueAccessor
+ {
+ private Type type;
+
+ public TypeValueAccessor(Type type)
+ {
+ this.type = type;
+ }
+
+ public override object Get(object context)
+ {
+ return type;
+ }
+
+ public override void Set(object context, object value)
+ {
+ throw new NotSupportedException("Cannot set the value of a type.");
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file