From e4cfc39ed2d29f67bfecee4a9d228b06ed64d416 Mon Sep 17 00:00:00 2001 From: eeichinger Date: Tue, 28 Jul 2009 16:59:40 +0000 Subject: [PATCH] polishing switch ObjectDefinitionValueResolver & related infrastructure code from using RootObjectDefinition to IObjectDefinition fixed SPRNET-1073 added PropertyOrFieldNode tests for injecting transparent proxies added new CollectionUtils.FindValuesOfType() method for filtering collections --- .../Expressions/PropertyOrFieldNode.cs | 4 +- .../Factory/Support/IManagedCollection.cs | 7 +- .../Factory/Support/ManagedDictionary.cs | 3 +- .../Objects/Factory/Support/ManagedList.cs | 3 +- .../Objects/Factory/Support/ManagedSet.cs | 3 +- .../Support/ObjectDefinitionValueResolver.cs | 35 +++--- .../Spring.Core/Spring.Core.2008.csproj | 1 + .../Spring.Core/Util/CollectionUtils.cs | 24 ++++ src/Spring/Spring.Core/Util/ObjectUtils.cs | 2 +- .../Validation/IValidationErrors.cs | 2 +- .../Expressions/PropertyOrFieldNodeTests.cs | 27 ++++- .../Factory/Support/ManagedDictionaryTests.cs | 6 +- .../Objects/TestTransparentProxyFactory.cs | 114 ++++++++++++++++++ .../Spring.Core.Tests.2008.csproj | 1 + 14 files changed, 200 insertions(+), 32 deletions(-) create mode 100644 test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs diff --git a/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs b/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs index ee62e639..ef8c8d3c 100644 --- a/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs +++ b/src/Spring/Spring.Core/Expressions/PropertyOrFieldNode.cs @@ -342,8 +342,8 @@ namespace Spring.Expressions throw new ArgumentException("Invalid value [" + newValue + "] for property or field '" + this.memberName + "' of primitive type [" + targetType + "]"); - } - else if (newValue == null || targetType.IsAssignableFrom(newValue.GetType())) + } + else if (newValue == null || ObjectUtils.IsAssignable(targetType, newValue)) // targetType.IsAssignableFrom(newValue.GetType()) { SetPropertyOrFieldValueInternal(context, newValue); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IManagedCollection.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IManagedCollection.cs index bb16bd5b..a79e3a88 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IManagedCollection.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IManagedCollection.cs @@ -21,7 +21,8 @@ #region Imports using System; -using System.Collections; +using System.Collections; +using Spring.Objects.Factory.Config; #endregion @@ -130,7 +131,7 @@ namespace Spring.Objects.Factory.Support /// this managed collection. /// /// A fully resolved collection. - ICollection Resolve(string objectName, RootObjectDefinition definition, + ICollection Resolve(string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver); } @@ -160,5 +161,5 @@ namespace Spring.Objects.Factory.Support /// /// A fully resolved element. public delegate object ManagedCollectionElementResolver( - string name, RootObjectDefinition definition, string argumentName, object element); + string name, IObjectDefinition definition, string argumentName, object element); } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ManagedDictionary.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ManagedDictionary.cs index 950038e0..4583497e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ManagedDictionary.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ManagedDictionary.cs @@ -31,6 +31,7 @@ using System.Globalization; using Spring.Core; using Spring.Core.TypeConversion; using Spring.Core.TypeResolution; +using Spring.Objects.Factory.Config; using Spring.Util; #endregion @@ -89,7 +90,7 @@ namespace Spring.Objects.Factory.Support /// /// A fully resolved collection. public ICollection Resolve( - string objectName, RootObjectDefinition definition, + string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) { IDictionary dictionary; diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ManagedList.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ManagedList.cs index ff65597b..89aeeb45 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ManagedList.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ManagedList.cs @@ -30,6 +30,7 @@ using System.Globalization; using Spring.Core; using Spring.Core.TypeConversion; using Spring.Core.TypeResolution; +using Spring.Objects.Factory.Config; using Spring.Util; #endregion @@ -75,7 +76,7 @@ namespace Spring.Objects.Factory.Support /// this managed collection. /// /// A fully resolved collection. - public ICollection Resolve(string objectName, RootObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) + public ICollection Resolve(string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) { IList list; diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ManagedSet.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ManagedSet.cs index 1d4ee2a5..7641de59 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ManagedSet.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ManagedSet.cs @@ -27,6 +27,7 @@ using Spring.Collections; using Spring.Core; using Spring.Core.TypeConversion; using Spring.Core.TypeResolution; +using Spring.Objects.Factory.Config; using Spring.Util; #endregion @@ -72,7 +73,7 @@ namespace Spring.Objects.Factory.Support /// this managed collection. /// /// A fully resolved collection. - public ICollection Resolve(string objectName, RootObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) + public ICollection Resolve(string objectName, IObjectDefinition definition, string propertyName, ManagedCollectionElementResolver resolver) { ISet set = new HybridSet(); diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs index e66ebc8c..6b4dc4b1 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2002-2008 the original author or authors. + * 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. @@ -25,10 +25,8 @@ using System.Globalization; using System.Runtime.Remoting; using Common.Logging; using Spring.Core.TypeConversion; -using Spring.Core.TypeResolution; using Spring.Expressions; using Spring.Objects.Factory.Config; -using Spring.Util; namespace Spring.Objects.Factory.Support { @@ -47,23 +45,16 @@ namespace Spring.Objects.Factory.Support private readonly ILog log; private readonly AbstractObjectFactory objectFactory; - private readonly string objectName; - private readonly IObjectDefinition objectDefinition; /// /// Initializes a new instance of the class. /// /// The object factory. - /// Name of the object. - /// The object definition. - public ObjectDefinitionValueResolver(AbstractObjectFactory objectFactory, string objectName, - IObjectDefinition objectDefinition) + public ObjectDefinitionValueResolver(AbstractObjectFactory objectFactory) { this.log = LogManager.GetLogger(this.GetType()); this.objectFactory = objectFactory; - this.objectName = objectName; - this.objectDefinition = objectDefinition; } /// @@ -116,9 +107,25 @@ namespace Spring.Objects.Factory.Support /// /// The value of the property that is being resolved. /// - public virtual object ResolveValueIfNecessary(string name, RootObjectDefinition definition, string argumentName, object argumentValue) + public virtual object ResolveValueIfNecessary(string name, IObjectDefinition definition, string argumentName, object argumentValue) { object resolvedValue = null; + resolvedValue = ResolvePropertyValue(name, definition, argumentName, argumentValue); + return resolvedValue; + } + + /// + /// TODO + /// + /// + /// + /// + /// + /// + private object ResolvePropertyValue(string name, IObjectDefinition definition, string argumentName, object argumentValue) + { + object resolvedValue = null; + // we must check the argument value to see whether it requires a runtime // reference to another object to be resolved. // if it does, we'll attempt to instantiate the object and set the reference. @@ -254,7 +261,7 @@ namespace Spring.Objects.Factory.Support /// /// The resolved object as defined by the inner object definition. /// - protected object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition, + protected virtual object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition, bool singletonOwner) { RootObjectDefinition mod = objectFactory.GetMergedObjectDefinition(innerObjectName, definition); @@ -324,7 +331,7 @@ namespace Spring.Objects.Factory.Support /// The runtime reference containing the value of the property. /// /// A reference to another object in the factory. - protected object ResolveReference(IConfigurableObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference) + protected virtual object ResolveReference(IObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference) { #region Instrumentation if (log.IsDebugEnabled) diff --git a/src/Spring/Spring.Core/Spring.Core.2008.csproj b/src/Spring/Spring.Core/Spring.Core.2008.csproj index 3b3c7ae5..99086967 100644 --- a/src/Spring/Spring.Core/Spring.Core.2008.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2008.csproj @@ -575,6 +575,7 @@ + diff --git a/src/Spring/Spring.Core/Util/CollectionUtils.cs b/src/Spring/Spring.Core/Util/CollectionUtils.cs index 90c6a0fc..10e064d2 100644 --- a/src/Spring/Spring.Core/Util/CollectionUtils.cs +++ b/src/Spring/Spring.Core/Util/CollectionUtils.cs @@ -303,6 +303,30 @@ namespace Spring.Util return val; } + /// + /// Finds a value of the given type in the given collection. + /// + /// The collection to search. + /// The type to look for. + /// a collection of matching values of the given type found, empty if none found, or null if the input collection was null. + public static ICollection FindValuesOfType(IEnumerable collection, Type type) + { + if (IsEmpty(collection)) + { + return null; + } + Type typeToUse = (type != null ? type : typeof(object)); + ArrayList results = new ArrayList(); + foreach (object obj in collection) + { + if (typeToUse.IsAssignableFrom(obj.GetType())) + { + results.Add(obj); + } + } + return results; + } + /// /// Find a value of one of the given types in the given Collection, /// searching the Collection for a value of the first type, then diff --git a/src/Spring/Spring.Core/Util/ObjectUtils.cs b/src/Spring/Spring.Core/Util/ObjectUtils.cs index 154de6d9..36929e88 100644 --- a/src/Spring/Spring.Core/Util/ObjectUtils.cs +++ b/src/Spring/Spring.Core/Util/ObjectUtils.cs @@ -296,7 +296,7 @@ namespace Spring.Util /// /// Determine if the given is assignable from the - /// given value, assuming setting by reflection. + /// given value, assuming setting by reflection and taking care of transparent proxies. /// /// ///

diff --git a/src/Spring/Spring.Core/Validation/IValidationErrors.cs b/src/Spring/Spring.Core/Validation/IValidationErrors.cs index b82dc43c..9ec469ed 100644 --- a/src/Spring/Spring.Core/Validation/IValidationErrors.cs +++ b/src/Spring/Spring.Core/Validation/IValidationErrors.cs @@ -53,7 +53,7 @@ namespace Spring.Validation /// /// The validation errors to merge; can be . /// - void MergeErrors(ValidationErrors errorsToMerge); + void MergeErrors(IValidationErrors errorsToMerge); ///

/// Gets the list of errors for the supplied error . diff --git a/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs index edceb78a..92746f4b 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/PropertyOrFieldNodeTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2008 the original author or authors. + * 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. @@ -18,12 +18,9 @@ #endregion -#region Imports - using System; using NUnit.Framework; - -#endregion +using Spring.Objects; namespace Spring.Expressions { @@ -31,13 +28,15 @@ namespace Spring.Expressions /// Tests the behavior of PropertyOrFieldNode expression node /// /// Erich Eichinger - /// $Id: $ [TestFixture] public class PropertyOrFieldNodeTests { private class BaseClass { + private ITestObject objectProp; + public string StringProp { get { return "BaseStringProp"; }} + public ITestObject ObjectProp { get { return objectProp; } set { objectProp = value; } } } private class DerivedClass : BaseClass @@ -54,5 +53,21 @@ namespace Spring.Expressions Assert.AreEqual(new DateTime(2008,1,1), ((IExpression) pofNode).GetValue(new DerivedClass())); } + + [Test] + public void CanSetTransparentProxy() + { + PropertyOrFieldNode pofNode = new PropertyOrFieldNode(); + pofNode.Text = "ObjectProp"; + + BaseClass ouc = new BaseClass(); + TestTransparentProxyFactory tpf = new TestTransparentProxyFactory(null, typeof(ITestObject), null); + object tpo = tpf.GetTransparentProxy(); + Assert.IsTrue( tpo is ITestObject ); + ITestObject itpo = tpo as ITestObject; + Assert.IsNotNull(itpo); + pofNode.SetValue( ouc, null, itpo); + Assert.AreSame( tpo, ouc.ObjectProp ); + } } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs index 3e245245..c48f9808 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Support/ManagedDictionaryTests.cs @@ -23,6 +23,8 @@ using System.Collections; using NUnit.Framework; #if NET_2_0 using System.Collections.Generic; +using Spring.Objects.Factory.Config; + #endif namespace Spring.Objects.Factory.Support @@ -48,7 +50,7 @@ namespace Spring.Objects.Factory.Support dict2.ValueTypeName = typeof(InternalType).FullName; IDictionary resolved = (IDictionary) dict2.Resolve("other", new RootObjectDefinition(typeof (object)), "prop", - delegate(string name, RootObjectDefinition definition, string argumentName, object element) + delegate(string name, IObjectDefinition definition, string argumentName, object element) { if ("stringValue".Equals(element)) { @@ -69,7 +71,7 @@ namespace Spring.Objects.Factory.Support dict.ValueTypeName = "System.Collections.Generic.List<[string]>"; IDictionary resolved = (IDictionary) dict.Resolve("somename", new RootObjectDefinition(typeof(object)), "prop", - delegate(string name, RootObjectDefinition definition, string argumentName, object element) + delegate(string name, IObjectDefinition definition, string argumentName, object element) { if ("value".Equals(element)) { diff --git a/test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs b/test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs new file mode 100644 index 00000000..1d8fedee --- /dev/null +++ b/test/Spring/Spring.Core.Tests/Objects/TestTransparentProxyFactory.cs @@ -0,0 +1,114 @@ +#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.Reflection; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Proxies; + +namespace Spring.Objects +{ + /// + /// + /// Erich Eichinger + public class TestTransparentProxyFactory : RealProxy, IRemotingTypeInfo + { + public delegate object InvokeCallback(object proxy, object targetInstance, MethodInfo targetMethod, object[] arguments); + + private object targetInstance; + private Type targetType; + private InvokeCallback invokeHandler; + + public object TargetInstance + { + get { return targetInstance; } + set { targetInstance = value; } + } + + public Type TargetType + { + get { return targetType; } + set { targetType = value; } + } + + public InvokeCallback InvokeHandler + { + get { return invokeHandler; } + set { invokeHandler = value; } + } + + public TestTransparentProxyFactory(object targetInstance, Type targetType, InvokeCallback invokeHandler) + : base(typeof(MarshalByRefObject)) + { + this.targetInstance = targetInstance; + this.targetType = targetType; + this.invokeHandler = invokeHandler; + } + + public override IMessage Invoke(IMessage msg) + { + if (msg is IMethodCallMessage) + { + IMethodCallMessage callMsg = (IMethodCallMessage)msg; + + // obtain method with same name & signature from target instance + MethodInfo targetMethod = targetInstance.GetType().GetMethod(callMsg.MethodName, (Type[])callMsg.MethodSignature); + + // invoke + object result; + if (invokeHandler != null) + { + result = invokeHandler(this, targetInstance, targetMethod, callMsg.Args); + } + else + { + result = targetMethod.Invoke(targetInstance, callMsg.Args); + } + + // create result msg + return new ReturnMessage(result, null, 0, null, callMsg); + } + throw new NotSupportedException(); + } + + public virtual bool CanCastTo(Type fromType, object o) + { + // we accept ALL messages... + return fromType.IsAssignableFrom(fromType); + } + + public virtual string TypeName + { + get { return targetInstance.GetType().AssemblyQualifiedName; } + set { throw new System.NotSupportedException(); } + } + + public static TestTransparentProxyFactory GetProxy(object transparentProxy ) + { + return (TestTransparentProxyFactory) RemotingServices.GetRealProxy(transparentProxy); + } + + public static object GetTargetInstance( object transparentProxy ) + { + return GetProxy(transparentProxy).targetInstance; + } + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj index 0e367bc8..9b0b77c2 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj @@ -630,6 +630,7 @@ Code + Code