Add autowire by attribute for fields, properties, methods and constructors
This commit is contained in:
@@ -136,5 +136,13 @@ namespace Spring.Core
|
||||
{
|
||||
get { return constructorInfo; }
|
||||
}
|
||||
|
||||
public Attribute[] GetParameterAttributes()
|
||||
{
|
||||
if (methodInfo != null)
|
||||
return Attribute.GetCustomAttributes(methodInfo.GetParameters()[parameterIndex]);
|
||||
else
|
||||
return Attribute.GetCustomAttributes(constructorInfo.GetParameters()[parameterIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2010-2011 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;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks a constructor, field, propery or config method as to be
|
||||
/// autowired by Spring's dependency injection facilities.
|
||||
///
|
||||
/// Only one constructor (at max) of any given bean class may carry this
|
||||
/// annotation, indicating the constructor to autowire when used as a Spring
|
||||
/// bean. Such a constructor does not have to be public.
|
||||
///
|
||||
/// Fields are injected right after construction of a object, before any
|
||||
/// config methods are invoked. Such a config field does not have to be public.
|
||||
///
|
||||
/// Config methods may have an arbitrary name and any number of arguments;
|
||||
/// each of those arguments will be autowired with a matching bean in the
|
||||
/// Spring container. Object property setter methods are effectively just
|
||||
/// a special case of such a general config method. Such config methods
|
||||
/// do not have to be public.
|
||||
///
|
||||
/// In the case of multiple argument methods, the 'required' parameter is
|
||||
/// applicable for all arguments.
|
||||
///
|
||||
/// In case of a {@link java.util.Collection} or {@link java.util.Map}
|
||||
/// dependency type, the container will autowire all beans matching the
|
||||
/// declared value type. In case of a Map, the keys must be declared as
|
||||
/// type String and will be resolved to the corresponding bean names.
|
||||
///
|
||||
/// Note that actual injection is performed through a
|
||||
/// {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
/// BeanPostProcessor} which in turn means that you <em>cannot</em>
|
||||
/// use {@code @Autowired} to inject references into
|
||||
/// {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
/// BeanPostProcessor} or
|
||||
/// {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor}
|
||||
/// types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
/// class (which, by default, checks for the presence of this annotation).
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Constructor)]
|
||||
public class AutowiredAttribute : Attribute
|
||||
{
|
||||
private bool _required = true;
|
||||
|
||||
/// <summary>
|
||||
/// Defines it Autowired PostProcessor should fail if object is not set
|
||||
/// </summary>
|
||||
public bool Required
|
||||
{
|
||||
get { return _required; }
|
||||
set { _required = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,639 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2010-2011 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.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using Spring.Collections;
|
||||
using Spring.Core;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Common.Logging;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IInstantiationAwareObjectPostProcessor"/> implementation
|
||||
/// that autowires annotated fields, properties and arbitrary config methods.
|
||||
/// Such members to be injected are detected through an attribute: by default,
|
||||
/// Spring's <see cref="AutowiredAttribute"/>.
|
||||
///
|
||||
/// Only one constructor (at max) of any given bean class may carry this
|
||||
/// annotation with the 'required' parameter set to <code>true</code>,
|
||||
/// indicating <i>the</i> constructor to autowire when used as a Spring bean.
|
||||
/// If multiple <i>non-required</i> constructors carry the annotation, they
|
||||
/// will be considered as candidates for autowiring. The constructor with
|
||||
/// the greatest number of dependencies that can be satisfied by matching
|
||||
/// beans in the Spring container will be chosen. If none of the candidates
|
||||
/// can be satisfied, then a default constructor (if present) will be used.
|
||||
/// An annotated constructor does not have to be public.
|
||||
///
|
||||
/// Fields are injected right after construction of a bean, before any
|
||||
/// config methods are invoked. Such a config field does not have to be public.
|
||||
///
|
||||
/// Config methods may have an arbitrary name and any number of arguments; each of
|
||||
/// those arguments will be autowired with a matching bean in the Spring container.
|
||||
/// Bean property setter methods are effectively just a special case of such a
|
||||
/// general config method. Config methods do not have to be public.
|
||||
///
|
||||
/// Note: A default AutowiredAttributeObjectPostProcessor will be registered
|
||||
/// by the "context:annotation-config" and "context:component-scan" XML tags.
|
||||
/// Remove or turn off the default annotation configuration there if you intend
|
||||
/// to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.
|
||||
/// <b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection;
|
||||
/// thus the latter configuration will override the former for properties wired through
|
||||
/// both approaches.
|
||||
/// </summary>
|
||||
public class AutowiredAttributeObjectPostProcessor : InstantiationAwareObjectPostProcessorAdapter,
|
||||
IObjectFactoryAware, IOrdered
|
||||
{
|
||||
private static readonly ILog Logger = LogManager.GetLogger<AutowiredAttributeObjectPostProcessor>();
|
||||
|
||||
private int _order = int.MaxValue - 2;
|
||||
|
||||
private static IConfigurableListableObjectFactory _objectFactory;
|
||||
|
||||
private SynchronizedHashtable _candidateConstructorsCache = new SynchronizedHashtable();
|
||||
|
||||
private readonly IDictionary<Type, InjectionMetadata> _injectionMetadataCache =
|
||||
new Dictionary<Type, InjectionMetadata>();
|
||||
|
||||
private Type _autowiredPropertyType = typeof (AutowiredAttribute);
|
||||
|
||||
/// <summary>
|
||||
/// Return the order value of this object, where a higher value means greater in
|
||||
/// terms of sorting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>Normally starting with 0 or 1, with <see cref="F:System.Int32.MaxValue"/> indicating
|
||||
/// greatest. Same order values will result in arbitrary positions for the affected
|
||||
/// objects.
|
||||
/// </p><p>Higher value can be interpreted as lower priority, consequently the first object
|
||||
/// has highest priority.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// The order value.
|
||||
/// </returns>
|
||||
public int Order
|
||||
{
|
||||
get { return _order; }
|
||||
private set { _order = value; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Callback that supplies the owning factory to an object instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Owning <see cref="T:Spring.Objects.Factory.IObjectFactory"/>
|
||||
/// (may not be <see langword="null"/>). The object can immediately
|
||||
/// call methods on the factory.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <p>Invoked after population of normal object properties but before an init
|
||||
/// callback like <see cref="T:Spring.Objects.Factory.IInitializingObject"/>'s
|
||||
/// <see cref="M:Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
|
||||
/// method or a custom init-method.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <exception cref="T:Spring.Objects.ObjectsException">In case of initialization errors.
|
||||
/// </exception>
|
||||
public IObjectFactory ObjectFactory
|
||||
{
|
||||
set { _objectFactory = (IConfigurableListableObjectFactory) value; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the used AutowiredAttributeType during the scan
|
||||
/// </summary>
|
||||
public Type AutowiredAttributeType
|
||||
{
|
||||
get { return _autowiredPropertyType; }
|
||||
set { _autowiredPropertyType = value; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines the candidate constructors to use for the given object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">The raw Type of the object.</param>
|
||||
/// <param name="objectName">Name of the object.</param>
|
||||
/// <returns>The candidate constructors, or <code>null</code> if none specified</returns>
|
||||
/// <exception cref="ObjectsException">in case of errors</exception>
|
||||
public override ConstructorInfo[] DetermineCandidateConstructors(Type objectType, string objectName)
|
||||
{
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
ConstructorInfo[] candidateConstructors = _candidateConstructorsCache.ContainsKey(objectType)
|
||||
? (ConstructorInfo[])_candidateConstructorsCache[objectType]
|
||||
: null;
|
||||
if (candidateConstructors == null)
|
||||
{
|
||||
lock (_candidateConstructorsCache)
|
||||
{
|
||||
candidateConstructors = _candidateConstructorsCache.ContainsKey(objectType)
|
||||
? (ConstructorInfo[])_candidateConstructorsCache[objectType]
|
||||
: null;
|
||||
if (candidateConstructors == null)
|
||||
{
|
||||
ConstructorInfo[] rawCandidates = objectType.GetConstructors();
|
||||
IList<ConstructorInfo> candidates = new List<ConstructorInfo>(rawCandidates.Length);
|
||||
ConstructorInfo requiredConstructor = null;
|
||||
ConstructorInfo defaultConstructor = null;
|
||||
foreach(var candidate in rawCandidates)
|
||||
{
|
||||
AutowiredAttribute attr =
|
||||
Attribute.GetCustomAttribute(candidate, typeof (AutowiredAttribute)) as AutowiredAttribute;
|
||||
if (attr != null)
|
||||
{
|
||||
if (requiredConstructor != null) {
|
||||
throw new ObjectCreationException("Invalid autowire-marked constructor: " + candidate +
|
||||
". Found another constructor with 'required' Autowired annotation: " +
|
||||
requiredConstructor);
|
||||
}
|
||||
if (candidate.GetParameters().Length == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Autowired annotation requires at least one argument: " + candidate);
|
||||
}
|
||||
if (attr.Required)
|
||||
{
|
||||
if (candidates.Count > 0)
|
||||
{
|
||||
throw new ObjectCreationException(
|
||||
"Invalid autowire-marked constructors: " + candidates +
|
||||
". Found another constructor with 'required' Autowired annotation: " +
|
||||
requiredConstructor);
|
||||
}
|
||||
requiredConstructor = candidate;
|
||||
}
|
||||
candidates.Add(candidate);
|
||||
}
|
||||
else if (candidate.GetParameters().Length == 0)
|
||||
{
|
||||
defaultConstructor = candidate;
|
||||
}
|
||||
}
|
||||
if (candidates.Count > 0)
|
||||
{
|
||||
// Add default constructor to list of optional constructors, as fallback.
|
||||
if (requiredConstructor == null && defaultConstructor != null) {
|
||||
candidates.Add(defaultConstructor);
|
||||
}
|
||||
candidateConstructors = candidates.ToArray();
|
||||
}
|
||||
else {
|
||||
candidateConstructors = new ConstructorInfo[0];
|
||||
}
|
||||
_candidateConstructorsCache.Add(objectType, candidateConstructors);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (candidateConstructors.Length > 0 ? candidateConstructors : null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds autowire candidates and verifies them
|
||||
/// </summary>
|
||||
/// <param name="objectType">
|
||||
/// The <see cref="System.Type"/> of the target object that is to be
|
||||
/// instantiated.
|
||||
/// </param>
|
||||
/// <param name="objectName">
|
||||
/// The name of the target object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The object to expose instead of a default instance of the target
|
||||
/// object.
|
||||
/// </returns>
|
||||
/// <exception cref="Spring.Objects.ObjectsException">
|
||||
/// In the case of any errors.
|
||||
/// </exception>
|
||||
/// <seealso cref="Spring.Objects.Factory.Support.AbstractObjectDefinition.HasObjectType"/>
|
||||
/// <seealso cref="Spring.Objects.Factory.Support.IConfigurableObjectDefinition.FactoryMethodName"/>
|
||||
public override object PostProcessBeforeInstantiation(Type objectType, string objectName)
|
||||
{
|
||||
var objectDefinition = _objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition;
|
||||
if (objectType != null)
|
||||
{
|
||||
var metadata = FindAutowiringMetadata(objectType);
|
||||
metadata.CheckConfigMembers(objectDefinition);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects autoried annotated properties, fields, methods into objectInstance
|
||||
/// </summary>
|
||||
/// <param name="pvs"></param>
|
||||
/// <param name="pis"></param>
|
||||
/// <param name="objectInstance"></param>
|
||||
/// <param name="objectName">Name of the object.</param>
|
||||
/// <returns>The actual property values to apply to the given object (can be the
|
||||
/// passed-in PropertyValues instances0 or null to skip property population.</returns>
|
||||
public override IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, IList<PropertyInfo> pis,
|
||||
object objectInstance, string objectName)
|
||||
{
|
||||
var metadata = FindAutowiringMetadata(objectInstance.GetType());
|
||||
try
|
||||
{
|
||||
metadata.Inject(objectInstance, objectName, pvs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ObjectCreationException(objectName, "Injection of autowired dependencies failed", ex);
|
||||
}
|
||||
return pvs;
|
||||
}
|
||||
|
||||
|
||||
private InjectionMetadata FindAutowiringMetadata(Type objectType)
|
||||
{
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = null;
|
||||
if (_injectionMetadataCache.ContainsKey(objectType))
|
||||
metadata = _injectionMetadataCache[objectType];
|
||||
|
||||
if (metadata == null)
|
||||
{
|
||||
lock (_injectionMetadataCache)
|
||||
{
|
||||
if (!_injectionMetadataCache.ContainsKey(objectType))
|
||||
{
|
||||
metadata = BuildAutowiringMetadata(objectType);
|
||||
_injectionMetadataCache.Add(objectType, metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private InjectionMetadata BuildAutowiringMetadata(Type objectType)
|
||||
{
|
||||
var elements = new List<InjectionMetadata.InjectedElement>();
|
||||
|
||||
do
|
||||
{
|
||||
var currElements = new List<InjectionMetadata.InjectedElement>();
|
||||
foreach (
|
||||
var property in
|
||||
objectType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
var attr = Attribute.GetCustomAttribute(property, _autowiredPropertyType) as AutowiredAttribute;
|
||||
if (attr != null && property.DeclaringType == objectType)
|
||||
currElements.Add(new AutowiredPropertyElement(property, attr.Required));
|
||||
}
|
||||
foreach (
|
||||
var field in
|
||||
objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
var attr = Attribute.GetCustomAttribute(field, _autowiredPropertyType) as AutowiredAttribute;
|
||||
if (attr != null && field.DeclaringType == objectType)
|
||||
currElements.Add(new AutowiredFieldElement(field, attr.Required));
|
||||
}
|
||||
foreach (
|
||||
var method in
|
||||
objectType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
var attr = Attribute.GetCustomAttribute(method, _autowiredPropertyType) as AutowiredAttribute;
|
||||
if (attr != null && method.DeclaringType == objectType)
|
||||
{
|
||||
if (method.IsStatic)
|
||||
{
|
||||
Logger.Warn(
|
||||
m => m("Autowired annotation is not supported on static methods: " + method.Name));
|
||||
continue;
|
||||
}
|
||||
if (method.IsGenericMethod)
|
||||
{
|
||||
Logger.Warn(
|
||||
m => m("Autowired annotation is not supported on generic methods: " + method.Name));
|
||||
continue;
|
||||
}
|
||||
currElements.Add(new AutowiredMethodElement(method, attr.Required));
|
||||
}
|
||||
}
|
||||
elements.InsertRange(0, currElements);
|
||||
objectType = objectType.BaseType;
|
||||
} while (objectType != null && objectType != typeof (Object));
|
||||
|
||||
return new InjectionMetadata(objectType, elements);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register the specified bean as dependent on the autowired beans.
|
||||
/// </summary>
|
||||
private static void RegisterDependentObjects(string objectName, IList autowiredObjectNames)
|
||||
{
|
||||
if (objectName == null) return;
|
||||
|
||||
var objectDefinition = _objectFactory.GetObjectDefinition(objectName) as RootObjectDefinition;
|
||||
IList<string> dependsOn = new List<string>(objectDefinition.DependsOn);
|
||||
foreach (var name in autowiredObjectNames)
|
||||
{
|
||||
var autowiredObjectName = name as string;
|
||||
if (!dependsOn.Contains(autowiredObjectName))
|
||||
{
|
||||
dependsOn.Add(autowiredObjectName);
|
||||
Logger.Debug(
|
||||
m =>
|
||||
m("Autowiring by type from object name '{0}' to object named '{1}'", objectName,
|
||||
autowiredObjectName));
|
||||
}
|
||||
}
|
||||
objectDefinition.DependsOn = dependsOn;
|
||||
}
|
||||
|
||||
private static object ResolvedCachedArgument(String objectName, Object cachedArgument)
|
||||
{
|
||||
if (cachedArgument is DependencyDescriptor)
|
||||
{
|
||||
var descriptor = (DependencyDescriptor) cachedArgument;
|
||||
return _objectFactory.ResolveDependency(descriptor, objectName, null);
|
||||
}
|
||||
else if (cachedArgument is RuntimeObjectReference)
|
||||
{
|
||||
return _objectFactory.GetObject(((RuntimeObjectReference) cachedArgument).ObjectName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return cachedArgument;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class representing injection information about an annotated field.
|
||||
/// </summary>
|
||||
private class AutowiredPropertyElement : InjectionMetadata.InjectedElement
|
||||
{
|
||||
|
||||
private readonly bool _required;
|
||||
|
||||
private bool _cached = false;
|
||||
|
||||
private Object _cachedFieldValue;
|
||||
|
||||
public AutowiredPropertyElement(PropertyInfo property, bool required)
|
||||
: base(property)
|
||||
{
|
||||
_required = required;
|
||||
}
|
||||
|
||||
public override void Inject(Object instance, String objectName, IPropertyValues pvs)
|
||||
{
|
||||
var property = (PropertyInfo) _member;
|
||||
try
|
||||
{
|
||||
Object value;
|
||||
if (_cached)
|
||||
{
|
||||
value = ResolvedCachedArgument(objectName, _cachedFieldValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var descriptor = new DependencyDescriptor(property, _required);
|
||||
IList autowiredObjectNames = new ArrayList();
|
||||
value = _objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames);
|
||||
lock (this)
|
||||
{
|
||||
if (!_cached)
|
||||
{
|
||||
if (value != null || _required)
|
||||
{
|
||||
_cachedFieldValue = descriptor;
|
||||
RegisterDependentObjects(objectName, autowiredObjectNames);
|
||||
if (autowiredObjectNames.Count == 1)
|
||||
{
|
||||
var autowiredBeanName = autowiredObjectNames[0] as string;
|
||||
if (_objectFactory.ContainsObject(autowiredBeanName))
|
||||
{
|
||||
if (_objectFactory.IsTypeMatch(autowiredBeanName, property.GetType()))
|
||||
{
|
||||
_cachedFieldValue = new RuntimeObjectReference(autowiredBeanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedFieldValue = null;
|
||||
}
|
||||
_cached = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value != null)
|
||||
{
|
||||
property.SetValue(instance, value, null);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ObjectCreationException("Could not autowire property: " + property, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class representing injection information about an annotated field.
|
||||
/// </summary>
|
||||
private class AutowiredFieldElement : InjectionMetadata.InjectedElement
|
||||
{
|
||||
|
||||
private readonly bool _required;
|
||||
|
||||
private bool _cached = false;
|
||||
|
||||
private Object _cachedFieldValue;
|
||||
|
||||
public AutowiredFieldElement(FieldInfo field, bool required)
|
||||
: base(field)
|
||||
{
|
||||
_required = required;
|
||||
}
|
||||
|
||||
public override void Inject(Object instance, String objectName, IPropertyValues pvs)
|
||||
{
|
||||
var field = (FieldInfo) _member;
|
||||
try
|
||||
{
|
||||
Object value;
|
||||
if (_cached)
|
||||
{
|
||||
value = ResolvedCachedArgument(objectName, _cachedFieldValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var descriptor = new DependencyDescriptor(field, _required);
|
||||
IList autowiredObjectNames = new ArrayList();
|
||||
value = _objectFactory.ResolveDependency(descriptor, objectName, autowiredObjectNames);
|
||||
lock (this)
|
||||
{
|
||||
if (!_cached)
|
||||
{
|
||||
if (value != null || _required)
|
||||
{
|
||||
_cachedFieldValue = descriptor;
|
||||
RegisterDependentObjects(objectName, autowiredObjectNames);
|
||||
if (autowiredObjectNames.Count == 1)
|
||||
{
|
||||
var autowiredBeanName = autowiredObjectNames[0] as string;
|
||||
if (_objectFactory.ContainsObject(autowiredBeanName))
|
||||
{
|
||||
if (_objectFactory.IsTypeMatch(autowiredBeanName, field.GetType()))
|
||||
{
|
||||
_cachedFieldValue = new RuntimeObjectReference(autowiredBeanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedFieldValue = null;
|
||||
}
|
||||
_cached = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value != null)
|
||||
{
|
||||
field.SetValue(instance, value);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ObjectCreationException("Could not autowire field: " + field, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Class representing injection information about an annotated method.
|
||||
///
|
||||
private class AutowiredMethodElement : InjectionMetadata.InjectedElement
|
||||
{
|
||||
private readonly bool _required;
|
||||
|
||||
private bool _cached = false;
|
||||
|
||||
private volatile Object[] _cachedMethodArguments;
|
||||
|
||||
public AutowiredMethodElement(MethodInfo method, bool required)
|
||||
: base(method)
|
||||
{
|
||||
_required = required;
|
||||
}
|
||||
|
||||
public override void Inject(Object target, string objectName, IPropertyValues pvs)
|
||||
{
|
||||
MethodInfo method = _member as MethodInfo;
|
||||
try
|
||||
{
|
||||
Object[] arguments;
|
||||
if (_cached)
|
||||
{
|
||||
arguments = ResolveCachedArguments(objectName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Type[] paramTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
|
||||
arguments = new Object[paramTypes.Length];
|
||||
var descriptors = new DependencyDescriptor[paramTypes.Length];
|
||||
IList autowiredBeanNames = new ArrayList();
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
descriptors[i] = new DependencyDescriptor(methodParam, _required);
|
||||
arguments[i] = _objectFactory.ResolveDependency(descriptors[i], objectName,
|
||||
autowiredBeanNames);
|
||||
if (arguments[i] == null && !_required)
|
||||
{
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lock (this)
|
||||
{
|
||||
if (!_cached)
|
||||
{
|
||||
if (arguments != null)
|
||||
{
|
||||
_cachedMethodArguments = new Object[arguments.Length];
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
_cachedMethodArguments[i] = descriptors[i];
|
||||
}
|
||||
RegisterDependentObjects(objectName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.Count == paramTypes.Length)
|
||||
{
|
||||
for (int i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
string autowiredBeanName = autowiredBeanNames[i] as string;
|
||||
if (_objectFactory.ContainsObject(autowiredBeanName))
|
||||
{
|
||||
if (_objectFactory.IsTypeMatch(autowiredBeanName, paramTypes[i]))
|
||||
{
|
||||
_cachedMethodArguments[i] =
|
||||
new RuntimeObjectReference(autowiredBeanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedMethodArguments = null;
|
||||
}
|
||||
_cached = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arguments != null)
|
||||
{
|
||||
method.Invoke(target, arguments);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ObjectCreationException("Could not autowire method: " + method, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] ResolveCachedArguments(string objectName)
|
||||
{
|
||||
if (_cachedMethodArguments == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Object[] arguments = new Object[_cachedMethodArguments.Length];
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
arguments[i] = ResolvedCachedArgument(objectName, _cachedMethodArguments[i]);
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2010-2011 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.Generic;
|
||||
using System.Reflection;
|
||||
using Common.Logging;
|
||||
using Spring.Objects;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal class for managing injection metadata.
|
||||
/// Not intended for direct use in applications.
|
||||
/// </summary>
|
||||
public class InjectionMetadata
|
||||
{
|
||||
private static readonly ILog Logger = LogManager.GetLogger<InjectionMetadata>();
|
||||
|
||||
private readonly IList<InjectedElement> _injectedElements;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="targetType"></param>
|
||||
/// <param name="elements"></param>
|
||||
public InjectionMetadata(Type targetType, IList<InjectedElement> elements)
|
||||
{
|
||||
_injectedElements = new List<InjectedElement>();
|
||||
if (elements.Count > 0)
|
||||
{
|
||||
foreach (var element in elements)
|
||||
{
|
||||
Logger.Debug(m => m("Found injected element on class [" + targetType.Name + "]: " + element));
|
||||
_injectedElements.Add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="objectDefinition"></param>
|
||||
public void CheckConfigMembers(RootObjectDefinition objectDefinition)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Inject values for members into object instance
|
||||
/// </summary>
|
||||
/// <param name="instance"></param>
|
||||
/// <param name="objectName"></param>
|
||||
/// <param name="pvs"></param>
|
||||
public void Inject(Object instance, string objectName, IPropertyValues pvs)
|
||||
{
|
||||
if (_injectedElements.Count == 0)
|
||||
return;
|
||||
|
||||
foreach(var element in _injectedElements)
|
||||
{
|
||||
Logger.Debug(m => m("Processing injected method of bean '{0}': {1}", objectName, element));
|
||||
element.Inject(instance, objectName, pvs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an element that needs to be injected
|
||||
/// </summary>
|
||||
public abstract class InjectedElement
|
||||
{
|
||||
/// <summary>
|
||||
/// The Property, field, method or constructor info
|
||||
/// </summary>
|
||||
protected readonly MemberInfo _member;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new inject element
|
||||
/// </summary>
|
||||
/// <param name="member"></param>
|
||||
protected InjectedElement(MemberInfo member)
|
||||
{
|
||||
_member = member;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ececuted to inject value to associated memeber info
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="requestingObjectName"></param>
|
||||
/// <param name="pvs"></param>
|
||||
public abstract void Inject(object target, string requestingObjectName, IPropertyValues pvs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// This annotation may be used on a field or parameter as a qualifier for
|
||||
/// candidate beans when autowiring. It may also be used to annotate other
|
||||
/// custom annotations that can then in turn be used as qualifiers.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
|
||||
public class QualifierAttribute : Attribute
|
||||
{
|
||||
private readonly string _name;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate a new qualifier type
|
||||
/// </summary>
|
||||
/// <param name="name">name to use as qualifier</param>
|
||||
public QualifierAttribute(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name associated with this qualifier
|
||||
/// </summary>
|
||||
public string Name { get { return _name; } }
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
using System;
|
||||
using Spring.Core;
|
||||
using System.Reflection;
|
||||
using Spring.Objects.Factory.Attributes;
|
||||
|
||||
namespace Spring.Objects.Factory.Config
|
||||
{
|
||||
@@ -34,6 +36,10 @@ namespace Spring.Objects.Factory.Config
|
||||
{
|
||||
private MethodParameter methodParameter;
|
||||
|
||||
private PropertyInfo property;
|
||||
|
||||
private FieldInfo field;
|
||||
|
||||
private readonly bool required;
|
||||
|
||||
private readonly bool eager;
|
||||
@@ -45,7 +51,8 @@ namespace Spring.Objects.Factory.Config
|
||||
/// </summary>
|
||||
/// <param name="methodParameter">The MethodParameter to wrap.</param>
|
||||
/// <param name="required">if set to <c>true</c> if the dependency is required.</param>
|
||||
public DependencyDescriptor(MethodParameter methodParameter, bool required) : this(methodParameter, required, true)
|
||||
public DependencyDescriptor(MethodParameter methodParameter, bool required)
|
||||
: this(methodParameter, required, true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -63,6 +70,55 @@ namespace Spring.Objects.Factory.Config
|
||||
this.eager = eager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new descriptor for a property.
|
||||
/// Considers the dependency as 'eager'.
|
||||
/// <param name="property">property to wrap</param>
|
||||
/// <param name="required">required whether the dependency is required</param>
|
||||
/// </summary>
|
||||
public DependencyDescriptor(PropertyInfo property, bool required)
|
||||
: this(property, required, true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new descriptor for a property.
|
||||
/// <param name="property">property to wrap</param>
|
||||
/// <param name="required ">whether the dependency is required</param>
|
||||
/// <param name="eager">whether this dependency is 'eager' in the sense of</param>
|
||||
/// eagerly resolving potential target beans for type matching
|
||||
/// </summary>
|
||||
public DependencyDescriptor(PropertyInfo property, bool required, bool eager)
|
||||
{
|
||||
this.property = property;
|
||||
this.required = required;
|
||||
this.eager = eager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new descriptor for a field.
|
||||
/// Considers the dependency as 'eager'.
|
||||
/// <param name="field">field to wrap</param>
|
||||
/// <param name="required">whether the dependency is required</param>
|
||||
/// </summary>
|
||||
public DependencyDescriptor(FieldInfo field, bool required)
|
||||
: this(field, required, true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new descriptor for a field.
|
||||
/// <param name="field">field to wrap</param>
|
||||
/// <param name="required ">whether the dependency is required</param>
|
||||
/// <param name="eager">whether this dependency is 'eager' in the sense of</param>
|
||||
/// eagerly resolving potential target beans for type matching
|
||||
/// </summary>
|
||||
public DependencyDescriptor(FieldInfo field, bool required, bool eager)
|
||||
{
|
||||
this.field = field;
|
||||
this.required = required;
|
||||
this.eager = eager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this dependency is required.
|
||||
@@ -79,7 +135,17 @@ namespace Spring.Objects.Factory.Config
|
||||
/// <value>The type of the dependency (never <code>null</code></value>
|
||||
public Type DependencyType
|
||||
{
|
||||
get { return methodParameter.ParameterType; }
|
||||
get
|
||||
{
|
||||
if (methodParameter != null)
|
||||
return methodParameter.ParameterType;
|
||||
if (property != null)
|
||||
return property.PropertyType;
|
||||
if (field != null)
|
||||
return field.FieldType;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,5 +167,83 @@ namespace Spring.Objects.Factory.Config
|
||||
{
|
||||
get { return methodParameter; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (methodParameter != null)
|
||||
return methodParameter.ParameterName();
|
||||
if (property != null)
|
||||
return property.Name;
|
||||
if (field != null)
|
||||
return field.Name;
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether the given dependency carries a value annotation.
|
||||
/// </summary>
|
||||
public Object GetSuggestedValue()
|
||||
{
|
||||
Object value = null;
|
||||
|
||||
if (methodParameter != null)
|
||||
value = ConvertFieldName(methodParameter.ParameterName());
|
||||
if (property != null)
|
||||
value = property.Name;
|
||||
if (field != null)
|
||||
value = ConvertFieldName(field.Name);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the qualifier name if exists
|
||||
/// </summary>
|
||||
public string GetQualifierName()
|
||||
{
|
||||
string value = null;
|
||||
|
||||
if (methodParameter != null)
|
||||
value = FindValue(methodParameter.GetParameterAttributes());
|
||||
if (property != null)
|
||||
value = FindValue(Attribute.GetCustomAttributes(property));
|
||||
if (field != null)
|
||||
value = FindValue(Attribute.GetCustomAttributes(field));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a suggested value from any of the given candidate annotations.
|
||||
*/
|
||||
|
||||
private string FindValue(Attribute[] attributesToSearch)
|
||||
{
|
||||
foreach (Attribute attribute in attributesToSearch)
|
||||
{
|
||||
if (attribute is QualifierAttribute)
|
||||
{
|
||||
var qualifierAttribute = attribute as QualifierAttribute;
|
||||
return qualifierAttribute.Name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string ConvertFieldName(string fieldName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fieldName))
|
||||
return string.Empty;
|
||||
|
||||
char[] letters = fieldName.TrimStart('_').ToCharArray();
|
||||
letters[0] = char.ToUpper(letters[0]);
|
||||
|
||||
return new string(letters);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1111,6 +1111,21 @@ namespace Spring.Objects.Factory.Support
|
||||
public override object ResolveDependency(DependencyDescriptor descriptor, string objectName,
|
||||
IList autowiredObjectNames)
|
||||
{
|
||||
string qualifierName = descriptor.GetQualifierName();
|
||||
if (!string.IsNullOrEmpty(qualifierName))
|
||||
{
|
||||
if (ContainsObject(qualifierName))
|
||||
{
|
||||
autowiredObjectNames.Add(qualifierName);
|
||||
return GetObject(qualifierName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (descriptor.Required)
|
||||
throw new NoSuchObjectDefinitionException(qualifierName, "no object found with this name");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Type type = descriptor.DependencyType;
|
||||
if (type.IsArray)
|
||||
{
|
||||
@@ -1133,6 +1148,38 @@ namespace Spring.Objects.Factory.Support
|
||||
}
|
||||
return TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects.Values, null);
|
||||
}
|
||||
else if (type.IsGenericType &&
|
||||
(type.GetGenericTypeDefinition() == typeof(IList<>) || type.GetGenericTypeDefinition() == typeof(Spring.Collections.Generic.ISet<>) ||
|
||||
type.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
|
||||
{
|
||||
var isDictionary = (type.GetGenericTypeDefinition() == typeof (IDictionary<,>));
|
||||
var elementType = isDictionary ? type.GetGenericArguments()[1] : type.GetGenericArguments()[0];
|
||||
|
||||
if (isDictionary && type.GetGenericArguments()[0] != typeof(string))
|
||||
throw new NoSuchObjectDefinitionException(type,
|
||||
"expected first generic to be a string but is " + type.GetGenericArguments()[0]);
|
||||
|
||||
IDictionary matchingObjects = FindAutowireCandidates(objectName, elementType, descriptor);
|
||||
if (matchingObjects.Count == 0)
|
||||
{
|
||||
if (descriptor.Required)
|
||||
{
|
||||
RaiseNoSuchObjectDefinitionException(elementType, "dictionary/list/set of " + elementType.FullName, descriptor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (autowiredObjectNames != null)
|
||||
{
|
||||
foreach (DictionaryEntry matchingObject in matchingObjects)
|
||||
{
|
||||
autowiredObjectNames.Add(matchingObject.Key);
|
||||
}
|
||||
}
|
||||
|
||||
return isDictionary
|
||||
? TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects, null)
|
||||
: TypeConversionUtils.ConvertValueIfNecessary(type, matchingObjects.Values, null);
|
||||
}
|
||||
else if (typeof(ICollection).IsAssignableFrom(type) && type.IsInterface)
|
||||
{
|
||||
//TODO - handle generic types.
|
||||
@@ -1142,6 +1189,20 @@ namespace Spring.Objects.Factory.Support
|
||||
else
|
||||
{
|
||||
IDictionary matchingObjects = FindAutowireCandidates(objectName, type, descriptor);
|
||||
if (matchingObjects.Count == 0 || matchingObjects.Count > 1)
|
||||
{
|
||||
Object value = descriptor.GetSuggestedValue();
|
||||
if (value is string)
|
||||
{
|
||||
string matchingObject = value as string;
|
||||
if (ContainsObject(matchingObject))
|
||||
{
|
||||
matchingObjects.Clear();
|
||||
matchingObjects.Add(matchingObject, GetObject(matchingObject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingObjects.Count == 0)
|
||||
{
|
||||
if (descriptor.Required)
|
||||
@@ -1155,9 +1216,8 @@ namespace Spring.Objects.Factory.Support
|
||||
}
|
||||
if (matchingObjects.Count > 1)
|
||||
{
|
||||
|
||||
throw new NoSuchObjectDefinitionException(type,
|
||||
"expected single matching object but found " + matchingObjects.Count + ": " + matchingObjects);
|
||||
"expected single matching object but found " + matchingObjects.Count + ": " + matchingObjects);
|
||||
}
|
||||
DictionaryEntry entry = (DictionaryEntry)ObjectUtils.EnumerateFirstElement(matchingObjects);
|
||||
if (autowiredObjectNames != null)
|
||||
@@ -1201,6 +1261,7 @@ namespace Spring.Objects.Factory.Support
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < candidateNames.Count; i++)
|
||||
{
|
||||
string candidateName = candidateNames[i];
|
||||
|
||||
@@ -675,6 +675,10 @@
|
||||
<Compile Include="Globalization\Resource.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Objects\Factory\Attributes\AutowiredAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\AutowiredAttributeObjectPostProcessor.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\InjectionMetadata.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\QualifierAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessor.cs" />
|
||||
<Compile Include="Objects\Factory\Config\AbstractConfigurer.cs" />
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2002-2011 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.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutowireAttributeCollectionTests
|
||||
{
|
||||
private GenericApplicationContext _applicationContext;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_applicationContext = new GenericApplicationContext();
|
||||
|
||||
var objDef = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor));
|
||||
objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE;
|
||||
_applicationContext.RegisterObjectDefinition("AutowiredAttributeObjectPostProcessor", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ColFoo1));
|
||||
_applicationContext.RegisterObjectDefinition("Foo1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ColFoo2));
|
||||
_applicationContext.RegisterObjectDefinition("Foo2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ColTestObject1));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("ColTestObject1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ColTestObject2));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("ColTestObject2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ColTestObject3));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("ColTestObject3", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ColTestObject4));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("ColTestObject4", objDef);
|
||||
|
||||
_applicationContext.Refresh();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAListOfObjects()
|
||||
{
|
||||
var testObj = (ColTestObject1)_applicationContext.GetObject("ColTestObject1");
|
||||
var objDef = _applicationContext.ObjectFactory.GetObjectDefinition("ColTestObject1");
|
||||
|
||||
Assert.That(testObj.Count, Is.EqualTo(2));
|
||||
Assert.That(objDef.DependsOn.Count, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectASetOfObjects()
|
||||
{
|
||||
var testObj = (ColTestObject2)_applicationContext.GetObject("ColTestObject2");
|
||||
|
||||
Assert.That(testObj.Count, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectADictionaryOfObjects()
|
||||
{
|
||||
var testObj = (ColTestObject3)_applicationContext.GetObject("ColTestObject3");
|
||||
|
||||
Assert.That(testObj.Count, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAnArrayOfObjects()
|
||||
{
|
||||
var testObj = (ColTestObject4)_applicationContext.GetObject("ColTestObject4");
|
||||
|
||||
Assert.That(testObj.Count, Is.EqualTo(2));
|
||||
}
|
||||
}
|
||||
|
||||
#region Test Objects
|
||||
|
||||
public interface IColFoo
|
||||
{
|
||||
string Name();
|
||||
}
|
||||
|
||||
public class ColFoo1 : IColFoo
|
||||
{
|
||||
public string Name()
|
||||
{
|
||||
return "Foo1";
|
||||
}
|
||||
}
|
||||
|
||||
public class ColFoo2 : IColFoo
|
||||
{
|
||||
public string Name()
|
||||
{
|
||||
return "Foo2";
|
||||
}
|
||||
}
|
||||
|
||||
public class ColTestObject1
|
||||
{
|
||||
[Autowired]
|
||||
private IList<IColFoo> _col;
|
||||
|
||||
public int Count { get { return _col.Count; } }
|
||||
}
|
||||
|
||||
public class ColTestObject2
|
||||
{
|
||||
[Autowired]
|
||||
private Spring.Collections.Generic.ISet<IColFoo> _col;
|
||||
|
||||
public int Count { get { return _col.Count; } }
|
||||
}
|
||||
|
||||
public class ColTestObject3
|
||||
{
|
||||
[Autowired]
|
||||
private IDictionary<string, IColFoo> _col;
|
||||
|
||||
public int Count { get { return _col.Count; } }
|
||||
}
|
||||
|
||||
public class ColTestObject4
|
||||
{
|
||||
[Autowired]
|
||||
private IColFoo[] _col;
|
||||
|
||||
public int Count { get { return _col.Length; } }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2002-2011 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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutowireAttributeConstructorTest
|
||||
{
|
||||
private GenericApplicationContext _applicationContext;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_applicationContext = new GenericApplicationContext();
|
||||
|
||||
var objDef = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor));
|
||||
objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE;
|
||||
_applicationContext.RegisterObjectDefinition("AutowiredAttributeObjectPostProcessor", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsSimple));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsSimple", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsAdvanced));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsAdvanced", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsHello));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsHello", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsCiao));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsCiao", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsTestObject1));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsTestObject1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsTestObject2));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsTestObject2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsTestObject3));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsTestObject3", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsTestObject4));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsTestObject4", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsTestObject5));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsTestObject5", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsTestObject6));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsTestObject6", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(ConsTestObject7));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("ConsTestObject7", objDef);
|
||||
|
||||
_applicationContext.Refresh();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConstructorWithInjectParameter()
|
||||
{
|
||||
var testObj = (ConsTestObject1)_applicationContext.GetObject("ConsTestObject1");
|
||||
|
||||
Assert.That(testObj.IsSet(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SelectInjectConstructorOverDefault()
|
||||
{
|
||||
var testObj = (ConsTestObject2)_applicationContext.GetObject("ConsTestObject2");
|
||||
|
||||
Assert.That(testObj.IsSet(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SelectConstructorWithMostParamters()
|
||||
{
|
||||
var testObj = (ConsTestObject3)_applicationContext.GetObject("ConsTestObject3");
|
||||
|
||||
Assert.That(testObj.IsSet(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailIfParameterAreRequired()
|
||||
{
|
||||
Exception ex = null;
|
||||
try
|
||||
{
|
||||
var testObj = (ConsTestObject4)_applicationContext.GetObject("ConsTestObject4");
|
||||
}
|
||||
catch (Exception e) { ex = e; }
|
||||
|
||||
Assert.That(ex, Is.Not.Null, "Exception should be thrown");
|
||||
Assert.That(ex.Message, Is.StringContaining("Unsatisfied dependency expressed"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectCollection()
|
||||
{
|
||||
var testObj = (ConsTestObject5)_applicationContext.GetObject("ConsTestObject5");
|
||||
|
||||
Assert.That(testObj.IsSet(), Is.True);
|
||||
Assert.That(testObj.ObjectCount(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void SetParameterByParameterName()
|
||||
{
|
||||
var testObj = (ConsTestObject6)_applicationContext.GetObject("ConsTestObject6");
|
||||
|
||||
Assert.That(testObj.IsSet(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetParameterByQualifier()
|
||||
{
|
||||
var testObj = (ConsTestObject7)_applicationContext.GetObject("ConsTestObject7");
|
||||
|
||||
Assert.That(testObj.IsSet(), Is.True);
|
||||
Assert.That(testObj.CorrectObject(), Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
#region Test Objects
|
||||
|
||||
public interface IConsSimple
|
||||
{
|
||||
string Message();
|
||||
}
|
||||
|
||||
public class ConsSimple : IConsSimple
|
||||
{
|
||||
public string Message()
|
||||
{
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
|
||||
public interface IConsAdvanced
|
||||
{
|
||||
string Message();
|
||||
}
|
||||
|
||||
public class ConsAdvanced : IConsAdvanced
|
||||
{
|
||||
public string Message()
|
||||
{
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
|
||||
public interface INotSet
|
||||
{
|
||||
}
|
||||
|
||||
public interface IConsCol
|
||||
{
|
||||
string Message();
|
||||
}
|
||||
|
||||
public class ConsHello : IConsCol
|
||||
{
|
||||
public string Message()
|
||||
{
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsCiao : IConsCol
|
||||
{
|
||||
public string Message()
|
||||
{
|
||||
return "ciao";
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsTestObject1
|
||||
{
|
||||
private IConsSimple _consSimple;
|
||||
|
||||
[Autowired]
|
||||
public ConsTestObject1(IConsSimple consSimple)
|
||||
{
|
||||
_consSimple = consSimple;
|
||||
}
|
||||
|
||||
public bool IsSet()
|
||||
{
|
||||
return _consSimple != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsTestObject2
|
||||
{
|
||||
private IConsSimple _consSimple;
|
||||
|
||||
public ConsTestObject2()
|
||||
{
|
||||
}
|
||||
|
||||
[Autowired]
|
||||
public ConsTestObject2(IConsSimple consSimple)
|
||||
{
|
||||
_consSimple = consSimple;
|
||||
}
|
||||
|
||||
public bool IsSet()
|
||||
{
|
||||
return _consSimple != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsTestObject3
|
||||
{
|
||||
private IConsSimple _consSimple;
|
||||
private IConsAdvanced _consAdvanced;
|
||||
|
||||
[Autowired(Required = false)]
|
||||
public ConsTestObject3(IConsSimple consSimple)
|
||||
{
|
||||
_consSimple = consSimple;
|
||||
}
|
||||
|
||||
[Autowired(Required = false)]
|
||||
public ConsTestObject3(IConsSimple consSimple, IConsAdvanced consAdvanced)
|
||||
{
|
||||
_consSimple = consSimple;
|
||||
_consAdvanced = consAdvanced;
|
||||
}
|
||||
|
||||
public bool IsSet()
|
||||
{
|
||||
return _consSimple != null && _consAdvanced != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsTestObject4
|
||||
{
|
||||
private INotSet _notSet;
|
||||
|
||||
[Autowired]
|
||||
public ConsTestObject4(INotSet notSet)
|
||||
{
|
||||
_notSet = notSet;
|
||||
}
|
||||
|
||||
public bool IsSet()
|
||||
{
|
||||
return _notSet != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsTestObject5
|
||||
{
|
||||
private IDictionary<string,IConsCol> _consCol;
|
||||
|
||||
[Autowired]
|
||||
public ConsTestObject5(IDictionary<string, IConsCol> consCol)
|
||||
{
|
||||
_consCol = consCol;
|
||||
}
|
||||
|
||||
public bool IsSet()
|
||||
{
|
||||
return _consCol != null;
|
||||
}
|
||||
|
||||
public int ObjectCount()
|
||||
{
|
||||
return _consCol.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsTestObject6
|
||||
{
|
||||
private IConsCol _consHello;
|
||||
|
||||
[Autowired]
|
||||
public ConsTestObject6(IConsCol consHello)
|
||||
{
|
||||
_consHello = consHello;
|
||||
}
|
||||
|
||||
public bool IsSet()
|
||||
{
|
||||
return _consHello != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsTestObject7
|
||||
{
|
||||
private IConsCol _consHello;
|
||||
|
||||
[Autowired]
|
||||
public ConsTestObject7([Qualifier("ConsCiao")] IConsCol consHello)
|
||||
{
|
||||
_consHello = consHello;
|
||||
}
|
||||
|
||||
public bool IsSet()
|
||||
{
|
||||
return _consHello != null;
|
||||
}
|
||||
|
||||
public bool CorrectObject()
|
||||
{
|
||||
return _consHello.Message() == "ciao";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright 2002-2010 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 NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutowireAttributeFieldTest
|
||||
{
|
||||
private GenericApplicationContext _applicationContext;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_applicationContext = new GenericApplicationContext();
|
||||
|
||||
var objDef = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor));
|
||||
objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE;
|
||||
_applicationContext.RegisterObjectDefinition("AutowiredAttributeObjectPostProcessor", objDef);
|
||||
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldFooImpl));
|
||||
_applicationContext.RegisterObjectDefinition("FldFoo", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldHello));
|
||||
_applicationContext.RegisterObjectDefinition("FldHello", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldCioa));
|
||||
_applicationContext.RegisterObjectDefinition("FldCioa", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldHola));
|
||||
_applicationContext.RegisterObjectDefinition("FldHola", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldTestObject1));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("FldTestObject1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldTestObject2));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("FldTestObject2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldTestObject3));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("FldTestObject3", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldTestObject4));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("FldTestObject4", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldTestObject5));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("FldTestObject5", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldTestObject6));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("FldTestObject6", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(FldTestObject7));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("FldTestObject7", objDef);
|
||||
|
||||
_applicationContext.Refresh();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectPropertyBasedOnFieldType()
|
||||
{
|
||||
var testObj = (FldTestObject1)_applicationContext.GetObject("FldTestObject1");
|
||||
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("FldTestObject1");
|
||||
|
||||
Assert.That(testObj.Test(), Is.EqualTo("foo"));
|
||||
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithTwoTypesRegisteredAndNoNameShouldFail()
|
||||
{
|
||||
Assert.That(delegate { var testObj = (FldTestObject2)_applicationContext.GetObject("FldTestObject2"); }, Throws.Exception.TypeOf<ObjectCreationException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithQualifierName()
|
||||
{
|
||||
var testObj = (FldTestObject3)_applicationContext.GetObject("FldTestObject3");
|
||||
|
||||
Assert.That(testObj.Say(), Is.EqualTo("cioa"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithTwoTypesAndNoQualifierUsePopertyName()
|
||||
{
|
||||
var testObj = (FldTestObject4)_applicationContext.GetObject("FldTestObject4");
|
||||
|
||||
Assert.That(testObj.Say(), Is.EqualTo("cioa"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailIfTypeCantBeResolved()
|
||||
{
|
||||
Exception ex = null;
|
||||
try
|
||||
{
|
||||
var testObj = (FldTestObject5)_applicationContext.GetObject("FldTestObject5");
|
||||
}
|
||||
catch (Exception e) { ex = e; }
|
||||
|
||||
Assert.That(ex, Is.Not.Null, "Should throw an exception");
|
||||
Assert.That(ex.Message, Is.StringContaining("Injection of autowired dependencies failed"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectedObjectAssignedToTwoInterfaces()
|
||||
{
|
||||
var testObj = (FldTestObject6)_applicationContext.GetObject("FldTestObject6");
|
||||
|
||||
Assert.That(testObj.Test(), Is.EqualTo("test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsNotRequired()
|
||||
{
|
||||
var testObj = (FldTestObject7)_applicationContext.GetObject("FldTestObject7");
|
||||
|
||||
Assert.That(testObj.IsNull(), Is.True);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region Test Objects
|
||||
|
||||
public interface IFldNotAnObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public interface IFldAnotherOne
|
||||
{
|
||||
string Quite();
|
||||
}
|
||||
|
||||
public interface IFldFoo
|
||||
{
|
||||
string Test();
|
||||
}
|
||||
|
||||
public class FldFooImpl : IFldFoo
|
||||
{
|
||||
public string Test()
|
||||
{
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
public interface IFldSay
|
||||
{
|
||||
string Say();
|
||||
}
|
||||
|
||||
public class FldHello : IFldSay
|
||||
{
|
||||
public string Say()
|
||||
{
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
||||
public class FldCioa : IFldSay
|
||||
{
|
||||
public string Say()
|
||||
{
|
||||
return "cioa";
|
||||
}
|
||||
}
|
||||
|
||||
public class FldHola : IFldFoo, IFldAnotherOne
|
||||
{
|
||||
public string Quite()
|
||||
{
|
||||
return "test";
|
||||
}
|
||||
|
||||
public string Test()
|
||||
{
|
||||
return "test";
|
||||
}
|
||||
}
|
||||
|
||||
public class FldTestObject1
|
||||
{
|
||||
[Autowired]
|
||||
private IFldFoo _fldFoo;
|
||||
|
||||
public string Test()
|
||||
{
|
||||
return _fldFoo.Test();
|
||||
}
|
||||
}
|
||||
|
||||
// object with 2 possibilities should fail
|
||||
public class FldTestObject2
|
||||
{
|
||||
[Autowired]
|
||||
private IFldSay _wrongName;
|
||||
|
||||
public string Say()
|
||||
{
|
||||
return _wrongName.Say();
|
||||
}
|
||||
}
|
||||
|
||||
// should not fail but inject Cioa object
|
||||
public class FldTestObject3
|
||||
{
|
||||
[Autowired]
|
||||
[Qualifier("FldCioa")]
|
||||
private IFldSay _fldCioa;
|
||||
|
||||
public string Say()
|
||||
{
|
||||
return _fldCioa.Say();
|
||||
}
|
||||
}
|
||||
|
||||
// should not fail but inject Hello via Propertyname
|
||||
public class FldTestObject4
|
||||
{
|
||||
[Autowired]
|
||||
private IFldSay _fldCioa;
|
||||
|
||||
public string Say()
|
||||
{
|
||||
return _fldCioa.Say();
|
||||
}
|
||||
}
|
||||
|
||||
// should not fail but inject Hello via Propertyname
|
||||
public class FldTestObject5
|
||||
{
|
||||
[Autowired]
|
||||
private IFldNotAnObject _ohhh;
|
||||
}
|
||||
|
||||
public class FldTestObject6
|
||||
{
|
||||
[Autowired]
|
||||
private IFldAnotherOne _hola;
|
||||
|
||||
public string Test()
|
||||
{
|
||||
return _hola.Quite();
|
||||
}
|
||||
}
|
||||
|
||||
public class FldTestObject7
|
||||
{
|
||||
[Autowired(Required = false)]
|
||||
private IFldNotAnObject _nono;
|
||||
|
||||
public bool IsNull()
|
||||
{
|
||||
return (_nono == null);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2002-2011 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.Generic;
|
||||
using NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutowireAttributeMethodsTests
|
||||
{
|
||||
private GenericApplicationContext _applicationContext;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_applicationContext = new GenericApplicationContext();
|
||||
|
||||
var objDef = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor));
|
||||
objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE;
|
||||
_applicationContext.RegisterObjectDefinition("AutowiredAttributeObjectPostProcessor", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(Simple));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("Simple", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodHello));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodHello", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodCiao));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodCiao", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject1));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject2));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject3));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject3", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject4));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject4", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject5));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject5", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject6));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject6", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject7));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject7", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject8));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject8", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(MethodTestObject9));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("MethodTestObject9", objDef);
|
||||
|
||||
_applicationContext.Refresh();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InObjectByType()
|
||||
{
|
||||
var testObj = (MethodTestObject1)_applicationContext.GetObject("MethodTestObject1");
|
||||
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("MethodTestObject1");
|
||||
|
||||
Assert.That(testObj.GetObject(), Is.Not.Null);
|
||||
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectByParamterName()
|
||||
{
|
||||
var testObj = (MethodTestObject2)_applicationContext.GetObject("MethodTestObject2");
|
||||
|
||||
Assert.That(testObj.GetObject(), Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectByQualifier()
|
||||
{
|
||||
var testObj = (MethodTestObject3)_applicationContext.GetObject("MethodTestObject3");
|
||||
|
||||
Assert.That(testObj.GetObject(), Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailIfTypeCantBeResolved()
|
||||
{
|
||||
Exception ex = null;
|
||||
try
|
||||
{
|
||||
var testObj = (FldTestObject5)_applicationContext.GetObject("MethodTestObject4");
|
||||
}
|
||||
catch (Exception e) { ex = e; }
|
||||
|
||||
Assert.That(ex, Is.Not.Null, "Should throw an exception");
|
||||
Assert.That(ex.Message, Is.StringContaining("Injection of autowired dependencies failed"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectListOfObjects()
|
||||
{
|
||||
var testObj = (MethodTestObject5)_applicationContext.GetObject("MethodTestObject5");
|
||||
|
||||
Assert.That(testObj.GetObject(), Is.Not.Null);
|
||||
Assert.That(testObj.GetObject().Count, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectSeveralParameters()
|
||||
{
|
||||
var testObj = (MethodTestObject6)_applicationContext.GetObject("MethodTestObject6");
|
||||
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("MethodTestObject6");
|
||||
|
||||
Assert.That(testObj.GetObject(), Is.Not.Null);
|
||||
Assert.That(testObj.GetSimple(), Is.Not.Null);
|
||||
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailIfObjecNotAvailable()
|
||||
{
|
||||
Assert.That(delegate { var testObj = (MethodTestObject7)_applicationContext.GetObject("MethodTestObject7"); },
|
||||
Throws.Exception.TypeOf<ObjectCreationException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PassIfObjectNotavailableButNotRequired()
|
||||
{
|
||||
var testObj1 = (MethodTestObject8)_applicationContext.GetObject("MethodTestObject8");
|
||||
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("MethodTestObject8");
|
||||
|
||||
Assert.That(testObj1.GetSimple(), Is.Null);
|
||||
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
|
||||
|
||||
var testObj2 = (MethodTestObject9)_applicationContext.GetObject("MethodTestObject9");
|
||||
objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("MethodTestObject9");
|
||||
|
||||
Assert.That(testObj2.GetrAdvanced(), Is.Null);
|
||||
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region Test Objects
|
||||
|
||||
public interface ISimple
|
||||
{
|
||||
string Foo();
|
||||
}
|
||||
|
||||
public class Simple : ISimple
|
||||
{
|
||||
public string Foo()
|
||||
{
|
||||
return "simple";
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAdvanced
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public interface IMethodFoo
|
||||
{
|
||||
string Foo();
|
||||
}
|
||||
|
||||
public class MethodHello : IMethodFoo
|
||||
{
|
||||
public string Foo()
|
||||
{
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodCiao : IMethodFoo
|
||||
{
|
||||
public string Foo()
|
||||
{
|
||||
return "ciao";
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject1
|
||||
{
|
||||
private ISimple _impl;
|
||||
|
||||
[Autowired]
|
||||
public void Prepare(ISimple impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public object GetObject()
|
||||
{
|
||||
return _impl;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject2
|
||||
{
|
||||
private IMethodFoo _methodCiao;
|
||||
|
||||
[Autowired]
|
||||
public void Prepare(IMethodFoo methodCiao)
|
||||
{
|
||||
_methodCiao = methodCiao;
|
||||
}
|
||||
|
||||
public object GetObject()
|
||||
{
|
||||
return _methodCiao;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject3
|
||||
{
|
||||
private IMethodFoo _impl;
|
||||
|
||||
[Autowired]
|
||||
public void Prepare([Qualifier("MethodHello")] IMethodFoo impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public object GetObject()
|
||||
{
|
||||
return _impl;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject4
|
||||
{
|
||||
private IMethodFoo _impl;
|
||||
|
||||
[Autowired]
|
||||
public void Prepare([Qualifier("MethodHello")] IMethodFoo impl, string test)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public object GetObject()
|
||||
{
|
||||
return _impl;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject5
|
||||
{
|
||||
private IList<IMethodFoo> _impl;
|
||||
|
||||
[Autowired]
|
||||
public void Prepare(IList<IMethodFoo> impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public IList<IMethodFoo> GetObject()
|
||||
{
|
||||
return _impl;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject6
|
||||
{
|
||||
private IMethodFoo _impl;
|
||||
private ISimple _simple;
|
||||
|
||||
[Autowired]
|
||||
public void Prepare(IMethodFoo methodHello, ISimple simple)
|
||||
{
|
||||
_impl = methodHello;
|
||||
_simple = simple;
|
||||
}
|
||||
|
||||
public object GetObject()
|
||||
{
|
||||
return _impl;
|
||||
}
|
||||
|
||||
public object GetSimple()
|
||||
{
|
||||
return _simple;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject7
|
||||
{
|
||||
private ISimple _simple;
|
||||
|
||||
[Autowired]
|
||||
public void Prepare([Qualifier("NotAvailable")] ISimple simple)
|
||||
{
|
||||
_simple = simple;
|
||||
}
|
||||
|
||||
public object GetSimple()
|
||||
{
|
||||
return _simple;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject8
|
||||
{
|
||||
private ISimple _simple;
|
||||
|
||||
[Autowired(Required = false)]
|
||||
public void Prepare([Qualifier("NotAvailable")] ISimple simple)
|
||||
{
|
||||
_simple = simple;
|
||||
}
|
||||
|
||||
public object GetSimple()
|
||||
{
|
||||
return _simple;
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodTestObject9
|
||||
{
|
||||
private IAdvanced _advanced;
|
||||
|
||||
[Autowired(Required = false)]
|
||||
public void Prepare(IAdvanced advanced)
|
||||
{
|
||||
_advanced = advanced;
|
||||
}
|
||||
|
||||
public object GetrAdvanced()
|
||||
{
|
||||
return _advanced;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2002-2011 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 NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutowireAttributePropertyTest
|
||||
{
|
||||
private GenericApplicationContext _applicationContext;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_applicationContext = new GenericApplicationContext();
|
||||
|
||||
var objDef = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor));
|
||||
objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE;
|
||||
_applicationContext.RegisterObjectDefinition("AutowiredAttributeObjectPostProcessor", objDef);
|
||||
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropFooImpl));
|
||||
_applicationContext.RegisterObjectDefinition("PropFoo", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropHello));
|
||||
_applicationContext.RegisterObjectDefinition("PropHello", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropCioa));
|
||||
_applicationContext.RegisterObjectDefinition("PropCioa", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropTestObject1));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("PropTestObject1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropTestObject2));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("PropTestObject2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropTestObject3));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("PropTestObject3", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropTestObject4));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("PropTestObject4", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PropTestObject5));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.RegisterObjectDefinition("PropTestObject5", objDef);
|
||||
|
||||
_applicationContext.Refresh();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectPropertyBasedOnPropertyType()
|
||||
{
|
||||
var testObj = (PropTestObject1)_applicationContext.GetObject("PropTestObject1");
|
||||
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("PropTestObject1");
|
||||
|
||||
Assert.That(testObj.Foo, Is.Not.Null);
|
||||
Assert.That(testObj.Test(), Is.EqualTo("foo"));
|
||||
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1), "Should have one Dependant Object");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithTwoTypesRegisteredAndNoNameShouldFail()
|
||||
{
|
||||
Assert.That(delegate { var testObj = (PropTestObject2)_applicationContext.GetObject("PropTestObject2"); }, Throws.Exception.TypeOf<ObjectCreationException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithQualifierName()
|
||||
{
|
||||
var testObj = (PropTestObject3)_applicationContext.GetObject("PropTestObject3");
|
||||
|
||||
Assert.That(testObj.Cioa, Is.Not.Null);
|
||||
Assert.That(testObj.Say(), Is.EqualTo("cioa"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithTwoTypesAndNoQualifierUsePopertyName()
|
||||
{
|
||||
var testObj = (PropTestObject4)_applicationContext.GetObject("PropTestObject4");
|
||||
|
||||
Assert.That(testObj.PropCioa, Is.Not.Null);
|
||||
Assert.That(testObj.Say(), Is.EqualTo("cioa"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailIfTypeCantBeResolved()
|
||||
{
|
||||
Exception ex = null;
|
||||
try
|
||||
{
|
||||
var testObj = (FldTestObject5)_applicationContext.GetObject("PropTestObject5");
|
||||
}
|
||||
catch (Exception e) { ex = e; }
|
||||
|
||||
Assert.That(ex, Is.Not.Null, "Should throw an exception");
|
||||
Assert.That(ex.Message, Is.StringContaining("Injection of autowired dependencies failed"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region Test Objects
|
||||
|
||||
public interface IPropNotAnObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public interface IPropFoo
|
||||
{
|
||||
string Test();
|
||||
}
|
||||
|
||||
public class PropFooImpl : IPropFoo
|
||||
{
|
||||
public string Test()
|
||||
{
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
public interface IPropSay
|
||||
{
|
||||
string PropSay();
|
||||
}
|
||||
|
||||
public class PropHello : IPropSay
|
||||
{
|
||||
public string PropSay()
|
||||
{
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
||||
public class PropCioa : IPropSay
|
||||
{
|
||||
public string PropSay()
|
||||
{
|
||||
return "cioa";
|
||||
}
|
||||
}
|
||||
|
||||
public class PropTestObject1
|
||||
{
|
||||
private IPropFoo _foo;
|
||||
|
||||
[Autowired]
|
||||
public IPropFoo Foo
|
||||
{
|
||||
get { return _foo; }
|
||||
set { _foo = value; }
|
||||
}
|
||||
|
||||
public string Test()
|
||||
{
|
||||
return _foo.Test();
|
||||
}
|
||||
}
|
||||
|
||||
public class PropTestObject2
|
||||
{
|
||||
private IPropSay _hello;
|
||||
|
||||
[Autowired]
|
||||
public IPropSay WrongName
|
||||
{
|
||||
get { return _hello; }
|
||||
set { _hello = value; }
|
||||
}
|
||||
|
||||
public string Say()
|
||||
{
|
||||
return _hello.PropSay();
|
||||
}
|
||||
}
|
||||
|
||||
// should not fail but inject Cioa object
|
||||
public class PropTestObject3
|
||||
{
|
||||
private IPropSay _cioa;
|
||||
|
||||
[Autowired]
|
||||
[Qualifier("PropCioa")]
|
||||
public IPropSay Cioa
|
||||
{
|
||||
get { return _cioa; }
|
||||
set { _cioa = value; }
|
||||
}
|
||||
|
||||
public string Say()
|
||||
{
|
||||
return _cioa.PropSay();
|
||||
}
|
||||
}
|
||||
|
||||
// should not fail but inject Hello via Propertyname
|
||||
public class PropTestObject4
|
||||
{
|
||||
private IPropSay _obj;
|
||||
|
||||
[Autowired]
|
||||
public IPropSay PropCioa
|
||||
{
|
||||
get { return _obj; }
|
||||
set { _obj = value; }
|
||||
}
|
||||
|
||||
public string Say()
|
||||
{
|
||||
return _obj.PropSay();
|
||||
}
|
||||
}
|
||||
|
||||
// should not fail but inject Hello via Propertyname
|
||||
public class PropTestObject5
|
||||
{
|
||||
private IPropNotAnObject _obj;
|
||||
|
||||
[Autowired]
|
||||
public IPropNotAnObject Ohhh
|
||||
{
|
||||
get { return _obj; }
|
||||
set { _obj = value; }
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -318,6 +318,11 @@
|
||||
</Compile>
|
||||
<Compile Include="HookableContextHandler.cs" />
|
||||
<Compile Include="Objects\ExpressionTestObject.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\AutowireAttributeCollectionTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\AutowireAttributeConstructorTest.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\AutowireAttributeFieldTest.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\AutowireAttributeMethodsTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\AutowireAttributePropertyTest.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\MyRequiredAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessorTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredTestObject.cs" />
|
||||
|
||||
Reference in New Issue
Block a user