/// <summary> /// Resolves the supplied generic <paramref name="typeName"/> to a /// <see cref="System.Type"/> instance. /// </summary> /// <param name="typeName"> /// The unresolved (possibly generic) name of a <see cref="System.Type"/>. /// </param> /// <returns> /// A resolved <see cref="System.Type"/> instance. /// </returns> /// <exception cref="System.TypeLoadException"> /// If the supplied <paramref name="typeName"/> could not be resolved /// to a <see cref="System.Type"/>. /// </exception> public override Type Resolve(string typeName) { if (StringUtils.IsNullOrEmpty(typeName)) { throw BuildTypeLoadException(typeName); } GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(typeName); Type type = null; try { if (genericInfo.ContainsGenericArguments) { type = TypeResolutionUtils.ResolveType(genericInfo.GenericTypeName); if (!genericInfo.IsGenericDefinition) { string[] unresolvedGenericArgs = genericInfo.GetGenericArguments(); Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; for (int i = 0; i < unresolvedGenericArgs.Length; i++) { genericArgs[i] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[i]); } type = type.MakeGenericType(genericArgs); } if (genericInfo.IsArrayDeclaration) { typeName = string.Format("{0}{1},{2}", type.FullName, genericInfo.GetArrayDeclaration(), type.Assembly.FullName); type = null; } } } catch (Exception ex) { if (ex is TypeLoadException) { throw; } throw BuildTypeLoadException(typeName, ex); } if (type == null) { type = base.Resolve(typeName); } return(type); }
/// <summary> /// Resolves the supplied generic <paramref name="typeName"/> to a /// <see cref="System.Type"/> instance. /// </summary> /// <param name="typeName"> /// The unresolved (possibly generic) name of a <see cref="System.Type"/>. /// </param> /// <returns> /// A resolved <see cref="System.Type"/> instance. /// </returns> /// <exception cref="System.TypeLoadException"> /// If the supplied <paramref name="typeName"/> could not be resolved /// to a <see cref="System.Type"/>. /// </exception> public override Type Resolve(string typeName) { if (StringUtils.IsNullOrEmpty(typeName)) { throw BuildTypeLoadException(typeName); } GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(typeName); Type type = null; try { if (genericInfo.ContainsGenericArguments) { type = TypeResolutionUtils.ResolveType(genericInfo.GenericTypeName); if (!genericInfo.IsGenericDefinition) { string[] unresolvedGenericArgs = genericInfo.GetGenericArguments(); Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; for (int i = 0; i < unresolvedGenericArgs.Length; i++) { genericArgs[i] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[i]); } type = type.MakeGenericType(genericArgs); } if (genericInfo.IsArrayDeclaration) { typeName = string.Format("{0}{1},{2}", type.FullName, genericInfo.GetArrayDeclaration(), type.Assembly.FullName); type = null; } } } catch (Exception ex) { if (ex is TypeLoadException) { throw; } throw BuildTypeLoadException(typeName, ex); } if (type == null) { type = base.Resolve(typeName); } return type; }
/// <summary> /// Instantiate an object instance using a named factory method. /// </summary> /// <remarks> /// <p> /// The method may be static, if the <paramref name="definition"/> /// parameter specifies a class, rather than a /// <see cref="Spring.Objects.Factory.IFactoryObject"/> instance, or an /// instance variable on a factory object itself configured using Dependency /// Injection. /// </p> /// <p> /// Implementation requires iterating over the static or instance methods /// with the name specified in the supplied <paramref name="definition"/> /// (the method may be overloaded) and trying to match with the parameters. /// We don't have the types attached to constructor args, so trial and error /// is the only way to go here. /// </p> /// </remarks> /// <param name="name"> /// The name associated with the supplied <paramref name="definition"/>. /// </param> /// <param name="definition"> /// The definition describing the instance that is to be instantiated. /// </param> /// <param name="arguments"> /// Any arguments to the factory method that is to be invoked. /// </param> /// <returns> /// The result of the factory method invocation (the instance). /// </returns> public virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments) { ObjectWrapper wrapper = new ObjectWrapper(); Type factoryClass = null; bool isStatic = true; ConstructorArgumentValues cargs = definition.ConstructorArgumentValues; ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues(); int expectedArgCount = 0; // we don't have arguments passed in programmatically, so we need to resolve the // arguments specified in the constructor arguments held in the object definition... if (arguments == null || arguments.Length == 0) { expectedArgCount = cargs.ArgumentCount; ResolveConstructorArguments(name, definition, wrapper, cargs, resolvedValues); } else { // if we have constructor args, don't need to resolve them... expectedArgCount = arguments.Length; } if (StringUtils.HasText(definition.FactoryObjectName)) { // it's an instance method on the factory object's class... factoryClass = objectFactory.GetObject(definition.FactoryObjectName).GetType(); isStatic = false; } else { // it's a static factory method on the object class... factoryClass = definition.ObjectType; } GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName); IList<MethodInfo> factoryMethodCandidates = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass); bool autowiring = (definition.AutowireMode == AutoWiringMode.Constructor); // try all matching methods to see if they match the constructor arguments... for (int i = 0; i < factoryMethodCandidates.Count; i++) { MethodInfo factoryMethodCandidate = factoryMethodCandidates[i]; if (genericArgsInfo.ContainsGenericArguments) { string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments(); if (factoryMethodCandidate.GetGenericArguments().Length != unresolvedGenericArgs.Length) continue; Type[] paramTypes = new Type[unresolvedGenericArgs.Length]; for (int j = 0; j < unresolvedGenericArgs.Length; j++) { paramTypes[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); } factoryMethodCandidate = factoryMethodCandidate.MakeGenericMethod(paramTypes); } if (arguments == null || arguments.Length == 0) { Type[] paramTypes = ReflectionUtils.GetParameterTypes(factoryMethodCandidate.GetParameters()); // try to create the required arguments... UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null; ArgumentsHolder args = CreateArgumentArray(name, definition, resolvedValues, wrapper, paramTypes, factoryMethodCandidate, autowiring, out unsatisfiedDependencyExceptionData); if (args == null) { arguments = null; // if we failed to match this method, keep // trying new overloaded factory methods... continue; } else { arguments = args.arguments; } } // if we get here, we found a usable candidate factory method - check, if arguments match //arguments = (arguments.Length == 0 ? null : arguments); if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethodCandidate }, arguments) == null) { continue; } object objectInstance = instantiationStrategy.Instantiate(definition, name, objectFactory, factoryMethodCandidate, arguments); wrapper.WrappedInstance = objectInstance; #region Instrumentation if (log.IsDebugEnabled) { log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethodCandidate)); } #endregion return wrapper; } // if we get here, we didn't match any method... throw new ObjectDefinitionStoreException( string.Format(CultureInfo.InvariantCulture, "Cannot find matching factory method '{0} on Type [{1}].", definition.FactoryMethodName, factoryClass)); }
/// <summary> /// Determines the <see cref="System.Type"/> of the object defined /// by the supplied object <paramref name="definition"/>. /// </summary> /// <param name="objectName"> /// The name associated with the supplied object <paramref name="definition"/>. /// </param> /// <param name="definition"> /// The <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/> /// that the <see cref="System.Type"/> is to be determined for. /// </param> /// <returns> /// The <see cref="System.Type"/> of the object defined by the supplied /// object <paramref name="definition"/>; or <see lang="null"/> if the /// <see cref="System.Type"/> cannot be determined. /// </returns> protected override Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition) { Type factoryType = null; bool isStatic = true; if (StringUtils.HasText(definition.FactoryObjectName)) { // check declared factory method return type on factory type... factoryType = GetType(definition.FactoryObjectName); isStatic = false; } else { factoryType = ResolveObjectType(definition, objectName); } if (factoryType == null) { return null; } // If all factory methods have the same return type, return that type. // Can't clearly figure out exact method due to type converting / autowiring! int minNrOfArgs = definition.ConstructorArgumentValues.GenericArgumentValues.Count; MethodInfo[] candidates = factoryType.GetMethods(); ISet returnTypes = new HybridSet(); foreach (MethodInfo factoryMethod in candidates) { #if NET_2_0 GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName); if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(genericArgsInfo.GenericMethodName) && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs && factoryMethod.GetGenericArguments().Length == genericArgsInfo.GetGenericArguments().Length) { if (genericArgsInfo.ContainsGenericArguments) { string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments(); Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; for (int j = 0; j < unresolvedGenericArgs.Length; j++) { genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); } returnTypes.Add(factoryMethod.MakeGenericMethod(genericArgs).ReturnType); } else { returnTypes.Add(factoryMethod.ReturnType); } } #else if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(definition.FactoryMethodName) && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs) { returnTypes.Add(factoryMethod.ReturnType); } #endif } if (returnTypes.Count == 1) { // clear return type found: all factory methods return same type... return (Type)ObjectUtils.EnumerateFirstElement(returnTypes); } // ambiguous return types found: return null to indicate "not determinable"... return null; }
/// <summary> /// Searches for and returns the method that is to be invoked. /// </summary> /// <remarks> /// The return value of this method call will subsequently be returned from the /// <see cref="Spring.Objects.Support.MethodInvoker.GetPreparedMethod()"/>. /// </remarks> /// <returns>The method that is to be invoked.</returns> /// <exception cref="System.MissingMethodException"> /// If no method could be found. /// </exception> /// <exception cref="System.ArgumentException"> /// If more than one method was found. /// </exception> protected virtual MethodInfo FindTheMethodToInvoke() { MethodInfo theMethod = null; Type targetType = (TargetObject != null) ? TargetObject.GetType() : TargetType; GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(TargetMethod); // if we don't have any named arguments, we can try to get the exact method first... if (NamedArguments.Count == 0) { ComposedCriteria searchCriteria = new ComposedCriteria(); searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName)); searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount)); searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length)); searchCriteria.Add(new MethodArgumentsCriteria(Arguments)); MemberInfo[] matchingMethods = targetType.FindMembers( MemberTypes.Method, MethodSearchingFlags, new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), searchCriteria); if (matchingMethods != null && matchingMethods.Length == 1) { theMethod = matchingMethods[0] as MethodInfo; } } if (theMethod == null) { // search for a method with a matching signature... ComposedCriteria searchCriteria = new ComposedCriteria(); searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName)); searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount)); searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length)); MemberInfo[] matchingMethods = targetType.FindMembers( MemberTypes.Method, MethodSearchingFlags, new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria), searchCriteria); if (matchingMethods.Length == 0) { throw new MissingMethodException(targetType.Name, TargetMethod); } if (matchingMethods.Length > 1) { throw new ArgumentException(string.Format( CultureInfo.InvariantCulture, "Unable to determine which exact method to call; found '{0}' matches.", matchingMethods.Length)); } theMethod = matchingMethods[0] as MethodInfo; } if (genericInfo.ContainsGenericArguments) { string[] unresolvedGenericArgs = genericInfo.GetGenericArguments(); Type[] genericArgs = new Type[unresolvedGenericArgs.Length]; for (int j = 0; j < unresolvedGenericArgs.Length; j++) { genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); } theMethod = theMethod.MakeGenericMethod(genericArgs); } return theMethod; }