SPRNET-1521 added AutowireAttributePostProcessor

This commit is contained in:
Steve Bohlen
2012-09-13 11:45:41 -04:00
57 changed files with 4338 additions and 19 deletions

View File

@@ -0,0 +1,110 @@
#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 System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Spring.Core
{
/// <summary>
/// Support class for <see cref="IAttributeAccessor"/>, providing
/// a base implementation of all methods. To be extended by subclasses.
/// </summary>
[Serializable]
public abstract class AttributeAccessorSupport : IAttributeAccessor
{
/** Map with String keys and Object values */
private readonly IDictionary<string, object> _attributes = new Dictionary<string, object>();
public virtual void SetAttribute(string name, object value)
{
Trace.Assert(name != null, "Name must not be null");
if (value != null) {
_attributes.Add(name, value);
}
else {
RemoveAttribute(name);
}
}
public virtual object GetAttribute(string name)
{
Trace.Assert(name != null, "Name must not be null");
if (_attributes.ContainsKey(name))
return _attributes[name];
return null;
}
public virtual object RemoveAttribute(string name) {
Trace.Assert(name != null, "Name must not be null");
if (_attributes.ContainsKey(name))
return _attributes.Remove(name);
return false;
}
public bool HasAttribute(string name)
{
Trace.Assert(name != null, "Name must not be null");
return _attributes.ContainsKey(name);
}
public String[] AttributeNames
{
get
{
return _attributes.Keys.ToArray();
}
}
/**
* Copy the attributes from the supplied AttributeAccessor to this accessor.
* @param source the AttributeAccessor to copy from
*/
protected void CopyAttributesFrom(IAttributeAccessor source) {
Trace.Assert(source != null, "Source must not be null");
string[] attributeNames = source.AttributeNames;
foreach(string attributeName in attributeNames)
{
SetAttribute(attributeName, source.GetAttribute(attributeName));
}
}
public override bool Equals(object other) {
if (this == other) {
return true;
}
if (!(other is AttributeAccessorSupport)) {
return false;
}
var that = (AttributeAccessorSupport) other;
return _attributes.Equals(that._attributes);
}
public override int GetHashCode()
{
return _attributes.GetHashCode();
}
}
}

View File

@@ -0,0 +1,76 @@
#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;
namespace Spring.Core
{
/// <summary>
/// Interface defining a generic contract for attaching and accessing metadata
/// to/from arbitrary objects.
/// </summary>
public interface IAttributeAccessor
{
/// <summary>
/// Set the attribute defined by <code>name</code> to the supplied <code>value</code>.
/// In general, users should take care to prevent overlaps with other
/// metadata attributes by using fully-qualified names, perhaps using
/// class or package names as prefix.
/// </summary>
/// <param name="name">the unique attribute key</param>
/// <param name="value">the attribute value to be attached</param>
void SetAttribute(string name, object value);
/// <summary>
/// Get the value of the attribute identified by <code>name</code>.
/// Return <code>null</code> if the attribute doesn't exist.
/// </summary>
/// <param name="name">the unique attribute key</param>
/// <returns>the current value of the attribute, if any</returns>
object GetAttribute(string name);
/// <summary>
/// Remove the attribute identified by <code>name</code> and return its value.
/// Return <code>null</code> if no attribute under <code>name</code> is found.
/// </summary>
/// <param name="name">the unique attribute key</param>
/// <returns>The last value of the attribute, if any</returns>
object RemoveAttribute(string name);
/// <summary>
/// Checks weather a specific attributes exists
/// </summary>
/// <param name="name">The unique attribute key</param>
/// <returns>
/// <code>true</code> if the attribute identified by <code>name</code> exists.
/// Otherwise return <code>false</code>
/// </returns>
bool HasAttribute(string name);
/// <summary>
/// Return the names of all attributes.
/// </summary>
String[] AttributeNames { get; }
}
}

View File

@@ -39,6 +39,7 @@ namespace Spring.Core
private ConstructorInfo constructorInfo;
private readonly int parameterIndex;
private Type parameterType;
/// <summary>
@@ -136,5 +137,34 @@ namespace Spring.Core
{
get { return constructorInfo; }
}
/// <summary>
/// Return the annotations associated with the specific method/constructor parameter.
/// </summary>
public Attribute[] ParameterAttributes
{
get
{
if (methodInfo != null)
return Attribute.GetCustomAttributes(methodInfo.GetParameters()[parameterIndex]);
else
return Attribute.GetCustomAttributes(constructorInfo.GetParameters()[parameterIndex]);
}
}
/// <summary>
/// Return the annotations associated with the target method/constructor itself.
/// </summary>
public Attribute[] MethodAttributes
{
get
{
if (methodInfo != null)
return Attribute.GetCustomAttributes(methodInfo);
else
return Attribute.GetCustomAttributes(constructorInfo);
}
}
}
}

View File

@@ -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; }
}
}
}

View File

@@ -0,0 +1,661 @@
#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 IList<Type> _autowiredPropertyTypes = new List<Type>();
/// <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>
/// Add a Autowired Attribute Type
/// </summary>
public void AddAutowiredType(Type attributeType)
{
if (!_autowiredPropertyTypes.Contains(attributeType))
_autowiredPropertyTypes.Add(attributeType);
}
/// <summary>
/// Create a new instance of an Autowire Post Processor
/// with standard attributes of <see cref="AutowiredAttribute"/>
/// and <see cref="ValueAttribute"/>
/// </summary>
public AutowiredAttributeObjectPostProcessor()
{
_autowiredPropertyTypes.Add(typeof(AutowiredAttribute));
_autowiredPropertyTypes.Add(typeof(ValueAttribute));
}
/// <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
{
foreach (var autowiredType in _autowiredPropertyTypes)
{
var currElements = new List<InjectionMetadata.InjectedElement>();
foreach (
var property in
objectType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance))
{
var required = true;
var attr = Attribute.GetCustomAttribute(property, autowiredType);
if (attr is AutowiredAttribute)
required = ((AutowiredAttribute)attr).Required;
if (attr != null && property.DeclaringType == objectType)
currElements.Add(new AutowiredPropertyElement(property, required));
}
foreach (
var field in
objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
{
var required = true;
var attr = Attribute.GetCustomAttribute(field, autowiredType);
if (attr is AutowiredAttribute)
required = ((AutowiredAttribute) attr).Required;
if (attr != null && field.DeclaringType == objectType)
currElements.Add(new AutowiredFieldElement(field, required));
}
foreach (
var method in
objectType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
{
var required = true;
var attr = Attribute.GetCustomAttribute(method, autowiredType);
if (attr is AutowiredAttribute)
required = ((AutowiredAttribute)attr).Required;
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, 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;
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,300 @@
#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 System.Collections.Generic;
using Spring.Collections.Generic;
using Spring.Core;
using Spring.Core.TypeConversion;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
using Spring.Util;
namespace Spring.Objects.Factory.Attributes
{
/// <summary>
/// <see cref="IAutowireCandidateResolver"/> implementation that matches bean definition qualifier
/// against <see cref="QualifierAttribute"/> on the field or parameter to be autowired.
/// Also supports suggested expression values through a <see cref="ValueAttribute"/> attribute.
/// </summary>
[Serializable]
public class QualifierAnnotationAutowireCandidateResolver : IAutowireCandidateResolver, IObjectFactoryAware
{
private IObjectFactory _objectFactory;
private Collections.Generic.ISet<Type> _qualifierTypes = new HashedSet<Type>();
private Type _valueAttributeType = typeof(ValueAttribute);
public IObjectFactory ObjectFactory
{
set { _objectFactory = value; }
}
public Type ValueAttributeType
{
set { _valueAttributeType = value; }
}
/// <summary>
/// Create a new QualifierAnnotationAutowireCandidateResolver
/// for Spring's standard <see cref="QualifierAttribute"/> attribute.
/// </summary>
public QualifierAnnotationAutowireCandidateResolver()
{
_qualifierTypes.Add(typeof(QualifierAttribute));
}
/// <summary>
/// Create a new QualifierAnnotationAutowireCandidateResolver
/// for the given qualifier attribute type.
/// </summary>
/// <param name="qualifierType">the qualifier attribute to look for</param>
public QualifierAnnotationAutowireCandidateResolver(Type qualifierType)
{
AssertUtils.ArgumentNotNull(qualifierType, "'qualifierType' must not be null");
_qualifierTypes.Add(qualifierType);
}
/// <summary>
/// Create a new QualifierAnnotationAutowireCandidateResolver
/// for the given qualifier attribute types.
/// </summary>
/// <param name="qualifierTypes">the qualifier annotations to look for</param>
public QualifierAnnotationAutowireCandidateResolver(Collections.Generic.ISet<Type> qualifierTypes) {
AssertUtils.ArgumentNotNull(qualifierTypes, "'qualifierTypes' must not be null");
foreach(var type in qualifierTypes)
{
if (!_qualifierTypes.Contains(type))
_qualifierTypes.Add(type);
}
}
/// <summary>
/// Register the given type to be used as a qualifier when autowiring.
/// <p>This identifies qualifier annotations for direct use (on fields,
/// method parameters and constructor parameters) as well as meta
/// annotations that in turn identify actual qualifier annotations.</p>
/// <p>This implementation only supports annotations as qualifier types.
/// The default is Spring's <see cref="QualifierAttribute"/> attribute which serves
/// as a qualifier for direct use and also as a meta attribute.</p>
/// </summary>
/// <param name="qualifierType">the attribute type to register</param>
public void AddQualifierType(Type qualifierType) {
_qualifierTypes.Add(qualifierType);
}
/// <summary>
/// Determine whether the provided object definition is an autowire candidate.
/// <p>To be considered a candidate the object's <em>autowire-candidate</em>
/// attribute must not have been set to 'false'. Also, if an attribute on
/// the field or parameter to be autowired is recognized by this bean factory
/// as a <em>qualifier</em>, the object must 'match' against the attribute as
/// well as any attributes it may contain. The bean definition must contain
/// the same qualifier or match by meta attributes. A "value" attribute will
/// fallback to match against the bean name or an alias if a qualifier or
/// attribute does not match.</p>
/// </summary>
public bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor)
{
if (!odHolder.ObjectDefinition.IsAutowireCandidate)
{
// if explicitly false, do not proceed with qualifier check
return false;
}
if (descriptor == null) {
// no qualification necessaryodHolder
return true;
}
bool match = CheckQualifiers(odHolder, descriptor.Attributes);
if (match)
{
MethodParameter methodParam = descriptor.MethodParameter;
if (methodParam != null)
{
var method = methodParam.MethodInfo;
if (method == null || method.ReturnType == typeof(void)) {
match = CheckQualifiers(odHolder, methodParam.MethodAttributes);
}
}
}
return match;
}
/// <summary>
/// Match the given qualifier annotations against the candidate bean definition.
/// </summary>
protected bool CheckQualifiers(ObjectDefinitionHolder odHolder, Attribute[] annotationsToSearch)
{
if (annotationsToSearch == null || annotationsToSearch.Length == 0) {
return true;
}
foreach (var attribute in annotationsToSearch)
{
if (IsQualifier(attribute.GetType()))
{
if (!CheckQualifier(odHolder, attribute))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Checks whether the given attribute type is a recognized qualifier type.
/// </summary>
protected bool IsQualifier(Type attributeType)
{
foreach (Type qualifierType in _qualifierTypes)
{
if (IsSubTypeOf(attributeType, qualifierType))
return true;
}
return false;
}
private bool IsSubTypeOf(Type actual, Type requested)
{
do
{
if (actual == requested)
return true;
actual = actual.BaseType;
} while (actual != typeof(Object));
return false;
}
/// <summary>
/// Match the given qualifier attribute against the candidate bean definition.
/// </summary>
protected bool CheckQualifier(ObjectDefinitionHolder odHolder, Attribute attribute)
{
Type type = attribute.GetType();
RootObjectDefinition od = (RootObjectDefinition) odHolder.ObjectDefinition;
AutowireCandidateQualifier qualifier = od.GetQualifier(type.FullName);
if (qualifier == null) {
qualifier = od.GetQualifier(type.Name);
}
if (qualifier == null) {
Attribute targetAttribute = null;
// TODO: Get the resolved factory method
//if (od.GetResolvedFactoryMethod() != null) {
// targetAttribute = Attribute.GetCustomAttribute(od.GetResolvedFactoryMethod(), type);
//}
if (targetAttribute == null) {
// look for matching attribute on the target class
if (_objectFactory != null) {
Type objectType = od.ObjectType;
if (objectType != null)
{
targetAttribute = Attribute.GetCustomAttribute(objectType, type);
}
}
if (targetAttribute == null && od.ObjectType != null) {
targetAttribute = Attribute.GetCustomAttribute(od.ObjectType, type);
}
}
if (targetAttribute != null && targetAttribute.Equals(attribute)) {
return true;
}
}
IDictionary<string, object> attributes = AttributeUtils.GetAttributeProperties(attribute);
if (attributes.Count == 0 && qualifier == null) {
// if no attributes, the qualifier must be present
return false;
}
foreach(var entry in attributes)
{
string propertyName = entry.Key;
object expectedValue = entry.Value;
object actualValue = null;
// check qualifier first
if (qualifier != null)
{
actualValue = qualifier.GetAttribute(propertyName);
}
if (actualValue == null)
{
// fall back on bean definition attribute
actualValue = od.GetAttribute(propertyName);
}
if (actualValue == null && propertyName.Equals(AutowireCandidateQualifier.VALUE_KEY) &&
expectedValue is string && odHolder.MatchesName((string) expectedValue))
{
// fall back on bean name (or alias) match
continue;
}
if (actualValue == null && qualifier != null)
{
// fall back on default, but only if the qualifier is present
actualValue = AttributeUtils.GetDefaultValue(attribute, propertyName);
}
if (actualValue != null)
{
actualValue = TypeConversionUtils.ConvertValueIfNecessary(expectedValue.GetType(), actualValue, null);
}
if (!expectedValue.Equals(actualValue)) {
return false;
}
}
return true;
}
/// <summary>
/// Determine whether the given dependency carries a value attribute.
/// </summary>
public Object GetSuggestedValue(DependencyDescriptor descriptor)
{
Object value = FindValue(descriptor.Attributes);
if (value == null)
{
MethodParameter methodParam = descriptor.MethodParameter;
if (methodParam != null)
{
value = FindValue(methodParam.MethodAttributes);
}
}
return value;
}
/// <summary>
/// Determine a suggested value from any of the given candidate annotations.
/// </summary>
protected Object FindValue(Attribute[] annotationsToSearch) {
foreach(var attribute in annotationsToSearch) {
if (_valueAttributeType == attribute.GetType())
{
Object value = ((ValueAttribute)attribute).Expression;
if (value == null)
{
throw new InvalidOperationException("Value attribute must have a value attribute");
}
return value;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,64 @@
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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public class QualifierAttribute : Attribute
{
private readonly string _value;
/// <summary>
/// Instantiate a new qualifier with an empty name
/// </summary>
public QualifierAttribute()
{
_value = "";
}
/// <summary>
/// Instantiate a new qualifier with a givin name
/// </summary>
/// <param name="value">name to use as qualifier</param>
public QualifierAttribute(string value)
{
_value = value;
}
/// <summary>
/// Gets the name associated with this qualifier
/// </summary>
public string Value { get { return _value; } }
/// <summary>
/// Checks weather the attribute is the same
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var o1 = obj as QualifierAttribute;
if (_value != o1._value) return false;
return true;
}
public override int GetHashCode()
{
return _value != null ? _value.GetHashCode() : 0;
}
}
}

View File

@@ -0,0 +1,37 @@
#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;
namespace Spring.Objects.Factory.Attributes
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public class ValueAttribute : Attribute
{
private string _expression;
public ValueAttribute(string expression)
{
_expression = expression;
}
public string Expression { get { return _expression; } }
}
}

View File

@@ -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,41 @@ namespace Spring.Objects.Factory.Config
{
get { return methodParameter; }
}
/// <summary>
/// Gets the Attributes assigned to Field, Property or Paramater
/// </summary>
public Attribute[] Attributes
{
get
{
if (methodParameter != null)
return methodParameter.ParameterAttributes;
if (property != null)
return Attribute.GetCustomAttributes(property);
if (field != null)
return Attribute.GetCustomAttributes(field);
return new Attribute[0];
}
}
/// <summary>
/// Gets the name of the member info
/// </summary>
public string DependencyName
{
get
{
if (methodParameter != null)
return methodParameter.ParameterName();
if (property != null)
return property.Name;
if (field != null)
return field.Name;
return "";
}
}
}
}

View File

@@ -22,6 +22,7 @@
using System;
using System.ComponentModel;
using Spring.Util;
#endregion
@@ -163,5 +164,17 @@ namespace Spring.Objects.Factory.Config
/// </param>
void RegisterCustomConverter(Type requiredType, TypeConverter converter);
/// <summary>
/// Add a String resolver for embedded values such as annotation attributes.
/// </summary>
/// <param name="valueResolver">the String resolver to apply to embedded values</param>
void AddEmbeddedValueResolver(IStringValueResolver valueResolver);
/// <summary>
/// Resolve the given embedded value, e.g. an annotation attribute.
/// </summary>
/// <param name="value">the value to resolve</param>
/// <returns>the resolved value (may be the original value as-is)</returns>
string ResolveEmbeddedValue(string value);
}
}

View File

@@ -226,5 +226,12 @@ namespace Spring.Objects.Factory.Config
/// <c>true</c> if this instance is autowire candidate; otherwise, <c>false</c>.
/// </value>
bool IsAutowireCandidate { get; }
/// <summary>
/// Return whether this bean is a primary autowire candidate.
/// If this value is true for exactly one bean among multiple
/// matching candidates, it will serve as a tie-breaker.
/// </summary>
bool IsPrimary { get; }
}
}

View File

@@ -132,6 +132,17 @@ namespace Spring.Objects.Factory.Config
get { return aliases; }
}
/// <summary>
/// Checks wether a givin candidate name has a defined object or alias
/// </summary>
/// <param name="candidateName">name to check if exists</param>
/// <returns></returns>
public bool MatchesName(string candidateName)
{
return (!string.IsNullOrEmpty(candidateName) &&
(candidateName.Equals(ObjectName) || Aliases.Contains(candidateName)));
}
#endregion
}
}

View File

@@ -28,6 +28,7 @@ using System.Globalization;
using Common.Logging;
using Spring.Collections;
using Spring.Util;
#endregion
@@ -247,13 +248,10 @@ namespace Spring.Objects.Factory.Config
definition.ResourceDescription, name, ex.Message);
}
}
factory.AddEmbeddedValueResolver(resolveAdapter);
}
/// <summary>
/// Parse values recursively to be able to resolve cross-references between
/// placeholder values.
@@ -401,7 +399,7 @@ namespace Spring.Objects.Factory.Config
#region Helper class
private class PlaceholderResolveHandlerAdapter
private class PlaceholderResolveHandlerAdapter : IStringValueResolver
{
private readonly PropertyPlaceholderConfigurer ppc;
private readonly NameValueCollection props;

View File

@@ -22,13 +22,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using Spring.Core.TypeResolution;
using Spring.Objects.Factory.Config;
using Spring.Util;
using Spring.Collections.Generic;
#endregion
@@ -44,7 +46,7 @@ namespace Spring.Objects.Factory.Support
/// <author>Juergen Hoeller</author>
/// <author>Rick Evans (.NET)</author>
[Serializable]
public abstract class AbstractObjectDefinition : IConfigurableObjectDefinition
public abstract class AbstractObjectDefinition : ObjectMetadataAttributeAccessor, IConfigurableObjectDefinition
{
private static readonly string SCOPE_SINGLETON = "singleton";
private static readonly string SCOPE_PROTOTYPE = "prototype";
@@ -135,6 +137,8 @@ namespace Spring.Objects.Factory.Support
InitMethodName = other.InitMethodName;
DestroyMethodName = other.DestroyMethodName;
IsAutowireCandidate = other.IsAutowireCandidate;
IsPrimary = other.IsPrimary;
CopyQualifiersFrom(aod);
DependsOn = new List<string>(other.DependsOn);
FactoryMethodName = other.FactoryMethodName;
FactoryObjectName = other.FactoryObjectName;
@@ -541,6 +545,67 @@ namespace Spring.Objects.Factory.Support
set { autowireCandidate = value;}
}
/// <summary>
/// Set whether this bean is a primary autowire candidate.
/// If this value is true for exactly one bean among multiple
/// matching candidates, it will serve as a tie-breaker.
/// </summary>
public bool IsPrimary
{
get { return primary; }
set { primary = value; }
}
/// <summary>
/// Register a qualifier to be used for autowire candidate resolution,
/// keyed by the qualifier's type name.
/// <see cref="AutowireCandidateQualifier"/>
/// </summary>
public void AddQualifier(AutowireCandidateQualifier qualifier)
{
qualifiers.Add(qualifier.TypeName, qualifier);
}
/// <summary>
/// Return whether this bean has the specified qualifier.
/// </summary>
public bool HasQualifier(string typeName)
{
return qualifiers.ContainsKey(typeName);
}
/// <summary>
/// Return the qualifier mapped to the provided type name.
/// </summary>
public AutowireCandidateQualifier GetQualifier(string typeName)
{
return qualifiers.ContainsKey(typeName) ? qualifiers[typeName] : null;
}
/// <summary>
/// Return all registered qualifiers.
/// </summary>
/// <returns>the Set of <see cref="AutowireCandidateQualifier"/> objects.</returns>
public Set<AutowireCandidateQualifier> GetQualifiers()
{
return new OrderedSet<AutowireCandidateQualifier>(qualifiers.Values);
}
/// <summary>
/// Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition.
/// </summary>
/// <param name="source">the AbstractBeanDefinition to copy from</param>
public void CopyQualifiersFrom(AbstractObjectDefinition source)
{
Trace.Assert(source != null, "Source must not be null");
foreach (var qualifier in source.qualifiers)
{
if (!qualifiers.Contains(qualifier))
qualifiers.Add(qualifier);
}
}
/// <summary>
/// The name of the initializer method.
/// </summary>
@@ -748,6 +813,7 @@ namespace Spring.Objects.Factory.Support
}
AutowireMode = other.AutowireMode;
ResourceDescription = other.ResourceDescription;
IsPrimary = other.IsPrimary;
AbstractObjectDefinition aod = other as AbstractObjectDefinition;
if (aod != null)
@@ -759,6 +825,7 @@ namespace Spring.Objects.Factory.Support
MethodOverrides.AddAll(aod.MethodOverrides);
DependencyCheck = aod.DependencyCheck;
CopyQualifiersFrom(aod);
}
}
@@ -779,6 +846,7 @@ namespace Spring.Objects.Factory.Support
buffer.Append("; Singleton = ").Append(IsSingleton);
buffer.Append("; LazyInit = ").Append(IsLazyInit);
buffer.Append("; Autowire = ").Append(AutowireMode);
buffer.Append("; Primary = ").Append(IsPrimary);
buffer.Append("; DependencyCheck = ").Append(DependencyCheck);
buffer.Append("; InitMethodName = ").Append(InitMethodName);
buffer.Append("; DestroyMethodName = ").Append(DestroyMethodName);
@@ -811,6 +879,12 @@ namespace Spring.Objects.Factory.Support
private DependencyCheckingMode dependencyCheck = DependencyCheckingMode.None;
private IList<string> dependsOn;
private bool autowireCandidate = true;
private bool primary;
private readonly IDictionary<string, AutowireCandidateQualifier> qualifiers =
new Dictionary<string, AutowireCandidateQualifier>();
private string initMethodName = null;
private string destroyMethodName = null;
private string factoryMethodName = null;

View File

@@ -1603,6 +1603,11 @@ namespace Spring.Objects.Factory.Support
/// </summary>
private ISet objectPostProcessors = new SortedSet(new ObjectOrderComparator());
/// <summary>
/// String Resolver applied to Autowired value injections
/// </summary>
private ISet embeddedValueResolvers = new SortedSet();
/// <summary>
/// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered
/// </summary>
@@ -2385,6 +2390,30 @@ namespace Spring.Objects.Factory.Support
return this.singletonsInCreation.Contains(name);
}
/// <summary>
/// Add a String resolver for embedded values such as annotation attributes.
/// </summary>
/// <param name="valueResolver">the String resolver to apply to embedded values</param>
public void AddEmbeddedValueResolver(IStringValueResolver valueResolver)
{
embeddedValueResolvers.Add(valueResolver);
}
/// <summary>
/// Resolve the given embedded value, e.g. an annotation attribute.
/// </summary>
/// <param name="value">the value to resolve</param>
/// <returns>the resolved value (may be the original value as-is)</returns>
public string ResolveEmbeddedValue(string value)
{
string result = value;
foreach(IStringValueResolver resolver in embeddedValueResolvers)
{
result = resolver.ParseAndResolveVariables(result);
}
return result;
}
/// <summary>
/// Add a new <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>
/// that will get applied to objects created by this factory.

View File

@@ -0,0 +1,102 @@
#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 System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Spring.Objects.Factory.Support
{
/// <summary>
/// Qualifier for resolving autowire candidates. A bean definition that
/// includes one or more such qualifiers enables fine-grained matching
/// against annotations on a field or parameter to be autowired.
/// </summary>
public class AutowireCandidateQualifier : ObjectMetadataAttributeAccessor
{
public static string VALUE_KEY = "Value";
private readonly string _typeName;
/// <summary>
/// Construct a qualifier to match against an annotation of the
/// given type.
/// </summary>
/// <param name="type">type the annotation type</param>
public AutowireCandidateQualifier(Type type) : this(type.Name)
{
}
/// <summary>
/// Construct a qualifier to match against an annotation of the
/// given type name.
/// <p>The type name may match the fully-qualified class name of
/// the annotation or the short class name (without the package).</p>
/// </summary>
/// <param name="typeName">the name of the annotation type</param>
public AutowireCandidateQualifier(string typeName)
{
Trace.Assert(typeName != null, "Type name must not be null");
_typeName = typeName;
}
/// <summary>
/// Construct a qualifier to match against an annotation of the
/// given type whose <code>value</code> attribute also matches
/// the specified value.
/// </summary>
/// <param name="type">the annotation type</param>
/// <param name="value">the annotation value to match</param>
public AutowireCandidateQualifier(Type type, object value) : this(type.Name, value)
{
}
/// <summary>
/// Construct a qualifier to match against an annotation of the
/// given type name whose <code>value</code> attribute also matches
/// the specified value.
/// <p>The type name may match the fully-qualified class name of
/// the annotation or the short class name (without the package).</p>
/// </summary>
/// <param name="typeName">the name of the annotation type</param>
/// <param name="value">the annotation value to match</param>
public AutowireCandidateQualifier(string typeName, object value)
{
Trace.Assert(typeName != null, "Type name must not be null");
_typeName = typeName;
SetAttribute(VALUE_KEY, value);
}
/// <summary>
/// Retrieve the type name. This value will be the same as the
/// type name provided to the constructor or the fully-qualified
/// class name if a Class instance was provided to the constructor.
/// </summary>
public String TypeName
{
get { return _typeName; }
}
}
}

View File

@@ -27,6 +27,7 @@ using System.Reflection;
using Spring.Collections;
using Spring.Core;
using Spring.Objects.Factory.Attributes;
using Spring.Objects.Factory.Config;
using Spring.Util;
@@ -348,7 +349,7 @@ namespace Spring.Objects.Factory.Support
/// <returns>A SimpleAutowireCandidateResolver</returns>
public static IAutowireCandidateResolver CreateAutowireCandidateResolver()
{
return new SimpleAutowireCandidateResolver();
return new QualifierAnnotationAutowireCandidateResolver();
}
/// <summary>

View File

@@ -25,6 +25,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using Common.Logging;
@@ -32,6 +33,8 @@ using Spring.Core;
using Spring.Core.TypeConversion;
using Spring.Objects.Factory.Config;
using Spring.Util;
using Spring.Expressions;
using Spring.Context.Support;
#endregion
@@ -324,7 +327,7 @@ namespace Spring.Objects.Factory.Support
/// <summary>
/// IDictionary from dependency type to corresponding autowired value
/// </summary>
private readonly IDictionary resolvableDependencies = new Hashtable();
private readonly IDictionary<Type, object> resolvableDependencies = new Dictionary<Type, object>();
#endregion
@@ -523,7 +526,7 @@ namespace Spring.Objects.Factory.Support
{
AssertUtils.IsTrue((autowiredValue is IObjectFactory) || dependencyType.IsInstanceOfType(autowiredValue),
"Value [" + autowiredValue + "] does not implement specified type [" + dependencyType.Name + "]");
if (!resolvableDependencies.Contains(dependencyType))
if (!resolvableDependencies.ContainsKey(dependencyType))
{
this.resolvableDependencies.Add(dependencyType, autowiredValue);
}
@@ -1112,6 +1115,19 @@ namespace Spring.Objects.Factory.Support
IList autowiredObjectNames)
{
Type type = descriptor.DependencyType;
Object value = AutowireCandidateResolver.GetSuggestedValue(descriptor);
if (value != null)
{
if (value is string)
{
object valueBefore = value;
value = ResolveEmbeddedValue((string) value);
if (valueBefore.Equals(value))
value = ExpressionEvaluator.GetValue(null, (string) value);
}
return TypeConversionUtils.ConvertValueIfNecessary(type, value, null);
}
if (type.IsArray)
{
Type elementType = type.GetElementType();
@@ -1133,6 +1149,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.
@@ -1155,9 +1203,17 @@ namespace Spring.Objects.Factory.Support
}
if (matchingObjects.Count > 1)
{
throw new NoSuchObjectDefinitionException(type,
"expected single matching object but found " + matchingObjects.Count + ": " + matchingObjects);
string primaryObjecName = DeterminePrimaryCandidate(matchingObjects, descriptor);
if (primaryObjecName == null)
{
throw new NoSuchObjectDefinitionException(type,
"expected single matching object but found " + matchingObjects.Count + ": " + matchingObjects);
}
if (autowiredObjectNames != null)
{
autowiredObjectNames.Add(primaryObjecName);
}
return matchingObjects[primaryObjecName];
}
DictionaryEntry entry = (DictionaryEntry)ObjectUtils.EnumerateFirstElement(matchingObjects);
if (autowiredObjectNames != null)
@@ -1168,7 +1224,75 @@ namespace Spring.Objects.Factory.Support
}
}
/// <summary>
/// Determine the primary autowire candidate in the given set of beans.
/// </summary>
/// <param name="candidateObjects">a Map of candidate names and candidate instances
/// that match the required type</param>
/// <param name="descriptor">the target dependency to match against</param>
/// <returns>the name of the primary candidate, or <code>null</code> if none found</returns>
private string DeterminePrimaryCandidate(IDictionary candidateObjects, DependencyDescriptor descriptor) {
string primaryObjectName = null;
string fallbackObjectName = null;
foreach(DictionaryEntry entry in candidateObjects)
{
string candidateBeanName = entry.Key as string;
object objectInstance = entry.Value;
if (IsPrimary(candidateBeanName, objectInstance))
{
if (primaryObjectName != null)
{
bool candidateLocal = ContainsObjectDefinition(candidateBeanName);
bool primaryLocal = ContainsObjectDefinition(primaryObjectName);
if (candidateLocal == primaryLocal)
{
throw new NoSuchObjectDefinitionException(descriptor.DependencyType,
"more than one 'primary' bean found among candidates: " + candidateObjects);
}
if (candidateLocal && !primaryLocal)
{
primaryObjectName = candidateBeanName;
}
}
else
{
primaryObjectName = candidateBeanName;
}
}
if (primaryObjectName == null &&
(resolvableDependencies.Values.Contains(objectInstance) ||
MatchesObjectName(candidateBeanName, descriptor.DependencyName)))
{
fallbackObjectName = candidateBeanName;
}
}
return (primaryObjectName != null ? primaryObjectName : fallbackObjectName);
}
/// <summary>
/// Return whether the object definition for the given object name has been
/// marked as a primary object.
/// </summary>
/// <param name="objectName">the name of the bean</param>
/// <param name="objectInstance">the corresponding bean instance</param>
/// <returns>whether the given bean qualifies as primary</returns>
private bool IsPrimary(string objectName, object objectInstance) {
if (ContainsObjectDefinition(objectName)) {
return GetMergedObjectDefinition(objectName, true).IsPrimary;
}
return (ParentObjectFactory is DefaultListableObjectFactory &&
((DefaultListableObjectFactory)ParentObjectFactory).IsPrimary(objectName, objectInstance));
}
/// <summary>
/// Determine whether the given candidate name matches the bean name or the aliases
///stored in this bean definition.
/// </summary>
protected bool MatchesObjectName(string objectName, string candidateName)
{
return (candidateName != null &&
(candidateName.Equals(objectName) || GetAliases(objectName).Contains(candidateName)));
}
/// <summary>
/// Raises the no such object definition exception for an unresolvable dependency
@@ -1188,9 +1312,9 @@ namespace Spring.Objects.Factory.Support
ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.Eager);
IDictionary result = new OrderedDictionary(candidateNames.Count);
foreach (DictionaryEntry entry in resolvableDependencies)
foreach (var entry in resolvableDependencies)
{
Type autoWiringType = (Type)entry.Key;
Type autoWiringType = entry.Key;
if (autoWiringType.IsAssignableFrom(requiredType))
{
object autowiringValue = this.resolvableDependencies[autoWiringType];
@@ -1201,6 +1325,7 @@ namespace Spring.Objects.Factory.Support
}
}
}
for (int i = 0; i < candidateNames.Count; i++)
{
string candidateName = candidateNames[i];

View File

@@ -18,6 +18,7 @@
#endregion
using System;
using Spring.Objects.Factory.Config;
namespace Spring.Objects.Factory.Support
@@ -41,5 +42,16 @@ namespace Spring.Objects.Factory.Support
/// <c>true</c> if the object definition qualifies as autowire candidate; otherwise, <c>false</c>.
/// </returns>
bool IsAutowireCandidate(ObjectDefinitionHolder odHolder, DependencyDescriptor descriptor);
/// <summary>
/// Determine whether a default value is suggested for the given dependency.
/// </summary>
/// <param name="descriptor">The descriptor for the target method parameter or field</param>
/// <returns>The value suggested (typically an expression String),
/// or <c>null</c> if none found
/// </returns>
Object GetSuggestedValue(DependencyDescriptor descriptor);
}
}

View File

@@ -45,5 +45,18 @@ namespace Spring.Objects.Factory.Support
{
return odHolder.ObjectDefinition.IsAutowireCandidate;
}
/// <summary>
/// Determine whether a default value is suggested for the given dependency.
/// </summary>
/// <param name="descriptor">The descriptor for the target method parameter or field</param>
/// <returns>The value suggested (typically an expression String),
/// or <c>null</c> if none found
/// </returns>
public object GetSuggestedValue(DependencyDescriptor descriptor)
{
return null;
}
}
}

View File

@@ -298,6 +298,11 @@ namespace Spring.Objects.Factory.Xml
/// </p>
/// </remarks>
public const string PropertyElement = "property";
/// <summary>
/// A qualifier definition used for fine grained autowiring
/// </summary>
public const string QualifierElement = "qualifier";
/// <summary>
/// A reference to another managed object or static
@@ -581,6 +586,16 @@ namespace Spring.Objects.Factory.Xml
/// </summary>
public const string AutowireAttribute = "autowire";
/// <summary>
/// Attribute element to farther deifne the qualifier of an object
/// </summary>
public const string AttributeElement = "attribute";
/// <summary>
/// The primary object for autwired injection
/// </summary>
public const string PrimaryAttribute = "primary";
/// <summary>
/// Shortcut alternative to specifying a key element in a
/// dictionary entry element with <c>&lt;ref object="..."/&gt;</c>.
@@ -598,6 +613,11 @@ namespace Spring.Objects.Factory.Xml
/// </summary>
public const string MergeAttribute = "merge";
/// <summary>
/// Defined meta attributes to be used for Autowire objects
/// </summary>
public const string MetaElement = "meta";
/// <summary>
/// The string of characters that delimit object names.
/// </summary>

View File

@@ -61,7 +61,7 @@ namespace Spring.Objects.Factory.Xml
NamespaceParser(
Namespace = "http://www.springframework.net",
SchemaLocationAssemblyHint = typeof(ObjectsNamespaceParser),
SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-1.3.xsd"
SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-2.0.xsd"
)
]
// [Obsolete("ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)]
@@ -446,6 +446,8 @@ namespace Spring.Objects.Factory.Xml
ParserContext childParserContext = new ParserContext(parserContext.ParserHelper, od);
ParseMetaElements(element, od);
ParseQualifierElements(id, element, parserContext, od);
MutablePropertyValues pvs = ParsePropertyElements(id, element, childParserContext);
ConstructorArgumentValues arguments = ParseConstructorArgSubElements(id, element, childParserContext);
EventValues events = ParseEventHandlerSubElements(id, element, childParserContext);
@@ -479,6 +481,12 @@ namespace Spring.Objects.Factory.Xml
autowire = childParserContext.ParserHelper.Defaults.Autowire;
}
od.AutowireMode = GetAutowireMode(autowire);
string primary = GetAttributeValue(element, ObjectDefinitionConstants.PrimaryAttribute);
if (primary == null)
{
primary = "false";
}
od.IsPrimary = IsTrueStringValue(primary);
string initMethodName = GetAttributeValue(element, ObjectDefinitionConstants.InitMethodAttribute);
if (StringUtils.HasText(initMethodName))
{
@@ -647,6 +655,76 @@ namespace Spring.Objects.Factory.Xml
return events;
}
/// <summary>
/// Parse the meta upplied meta attributes if the given object element
/// </summary>
protected void ParseMetaElements(XmlElement element, ObjectMetadataAttributeAccessor attributeAccessor)
{
foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.MetaElement))
{
string key = GetAttributeValue((XmlElement)node, ObjectDefinitionConstants.KeyAttribute);
string value = GetAttributeValue((XmlElement)node, ObjectDefinitionConstants.ValueAttribute);
ObjectMetadataAttribute attribute = new ObjectMetadataAttribute(key, value);
attribute.Source = (XmlElement)node;
attributeAccessor.AddMetadataAttribute(attribute);
}
}
/// <summary>
/// Parse qualifier sub-elements of the given bean element.
/// </summary>
public void ParseQualifierElements(string name, XmlElement element, ParserContext parserContext, AbstractObjectDefinition od)
{
foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.QualifierElement))
{
ParseQualifierElement(name, (XmlElement) node, parserContext, od);
}
}
/// <summary>
/// Parse a qualifier element.
/// </summary>
public void ParseQualifierElement(string name, XmlElement element, ParserContext parserContext, AbstractObjectDefinition od)
{
string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute);
string value = GetAttributeValue(element, ObjectDefinitionConstants.ValueAttribute);
if (string.IsNullOrEmpty(typeName))
{
throw new ObjectDefinitionStoreException(
parserContext.ReaderContext.Resource, name,
"Tag 'qualifier' must have a 'type' attribute");
}
var qualifier = new AutowireCandidateQualifier(typeName);
qualifier.Source = element;
if (!string.IsNullOrEmpty(value))
qualifier.SetAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.AttributeElement))
{
var attributeEle = node as XmlElement;
string attributeKey = GetAttributeValue(attributeEle, ObjectDefinitionConstants.KeyAttribute);
string attributeValue = GetAttributeValue(attributeEle, ObjectDefinitionConstants.ValueAttribute);
if (!string.IsNullOrEmpty(attributeKey) && !string.IsNullOrEmpty(attributeValue))
{
var attribute = new ObjectMetadataAttribute(attributeKey, attributeValue);
attribute.Source = attributeEle;
qualifier.AddMetadataAttribute(attribute);
}
else
{
throw new ObjectDefinitionStoreException(
parserContext.ReaderContext.Resource, name,
"Qualifier 'attribute' tag must have a 'key' and 'value'");
}
}
od.AddQualifier(qualifier);
}
/// <summary>
/// Parse property value subelements of the given object element.
/// </summary>

View File

@@ -0,0 +1,595 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.springframework.net" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" targetNamespace="http://www.springframework.net" elementFormDefault="qualified" attributeFormDefault="unqualified" vs:friendlyname="Spring.NET Configuration" vs:ishtmlschema="false" vs:iscasesensitive="true" vs:requireattributequotes="true" vs:defaultnamespacequalifier="" vs:defaultnsprefix="">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Spring Objects XML Schema Definition
Based on Spring Beans DTD, authored by Rod Johnson &amp; Juergen Hoeller
Author: Griffin Caprio
This defines a simple and consistent way of creating a namespace
of managed objects configured by a Spring XmlObjectFactory.
This document type is used by most Spring functionality, including
web application contexts, which are based on object factories.
Each object element in this document defines an object.
Typically the object type (System.Type is specified, along with plain vanilla
object properties.
Object instances can be "singletons" (shared instances) or "prototypes"
(independent instances).
References among objects are supported, i.e. setting an object property
to refer to another object in the same factory or an ancestor factory.
As alternative to object references, "inner object definitions" can be used.
Singleton flags and names of such "inner object" are always ignored:
Inner object are anonymous prototypes.
There is also support for lists, dictionaries, and sets.
]]>
</xsd:documentation>
</xsd:annotation>
<!-- base types -->
<xsd:complexType name="identifiedType" abstract="true">
<xsd:annotation>
<xsd:documentation><![CDATA[The unique identifier for a bean. The scope of the identifier is the enclosing object factory.]]></xsd:documentation>
</xsd:annotation>
<xsd:attribute name="id" type="xsd:ID">
<xsd:annotation>
<xsd:documentation><![CDATA[The unique identifier for an object.]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:simpleType name="nonNullString">
<xsd:annotation>
<xsd:documentation>Defines a base type for any required string. Defines a string with a minimum length of 0</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:minLength value="0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="description">
<xsd:annotation>
<xsd:documentation>
Element containing informative text describing the purpose of the enclosing
element. Always optional.
Used primarily for user documentation of XML object definition documents.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="nonNullString"/>
</xsd:simpleType>
<xsd:complexType name="valueObject">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="type" type="nonNullString" use="optional"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="expression">
<xsd:sequence>
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="2"/>
</xsd:sequence>
<xsd:attribute name="value" type="nonNullString" use="required"/>
</xsd:complexType>
<!--
Defines a reference to another object in this factory or an external
factory (parent or included factory).
-->
<xsd:complexType name="objectReference">
<xsd:attribute name="object" type="nonNullString" use="optional"/>
<xsd:attribute name="local" type="xsd:IDREF" use="optional"/>
<xsd:attribute name="parent" type="nonNullString" use="optional"/>
<!--
References must specify a name of the target object.
The "object" attribute can reference any name from any object in the context,
to be checked at runtime.
Local references, using the "local" attribute, have to use object ids;
they can be checked by this DTD, thus should be preferred for references
within the same object factory XML file.
-->
</xsd:complexType>
<!-- Defines a reference to another object or a type. -->
<xsd:complexType name="objectOrClassReference">
<xsd:attribute name="object" type="nonNullString" use="optional"/>
<xsd:attribute name="local" type="xsd:IDREF" use="optional"/>
<xsd:attribute name="type" type="nonNullString" use="optional"/>
</xsd:complexType>
<xsd:group name="objectList">
<xsd:sequence>
<xsd:element name="description" type="description" minOccurs="0"/>
<xsd:choice>
<xsd:element name="object" type="vanillaObject"/>
<!--
Defines a reference to another object in this factory or an external
factory (parent or included factory).
-->
<xsd:element name="ref" type="objectReference"/>
<!--
Defines a string property value, which must also be the id of another
object in this factory or an external factory (parent or included factory).
While a regular 'value' element could instead be used for the same effect,
using idref in this case allows validation of local object ids by the xml
parser, and name completion by helper tools.
-->
<xsd:element name="idref" type="objectReference"/>
<!--
A objectList can contain multiple inner object, ref, collection, or value elements.
Lists are untyped, pending generics support, although references will be
strongly typed.
A objectList can also map to an array type. The necessary conversion
is automatically performed by AbstractObjectFactory.
-->
<xsd:element name="list">
<xsd:complexType>
<xsd:group ref="objectList" minOccurs="0" maxOccurs="unbounded"/>
<xsd:attribute name="element-type" type="nonNullString" use="optional"/>
<xsd:attribute name="merge" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
</xsd:element>
<!--
A set can contain multiple inner object, ref, collection, or value elements.
Sets are untyped, pending generics support, although references will be
strongly typed.
-->
<xsd:element name="set">
<xsd:complexType>
<xsd:group ref="objectList" minOccurs="0" maxOccurs="unbounded"/>
<xsd:attribute name="element-type" type="nonNullString" use="optional"/>
<xsd:attribute name="merge" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
</xsd:element>
<!--
A Spring map is a mapping from a string key to object (a .NET IDictionary).
Maps may be empty.
-->
<xsd:element name="dictionary" type="objectMap"/>
<!--
Name-values elements differ from map elements in that values must be strings.
Name-values may be empty.
-->
<xsd:element name="name-values" type="objectNameValues"/>
<!--
Contains a string representation of a property value.
The property may be a string, or may be converted to the
required type using the System.ComponentModel.TypeConverter
machinery. This makes it possible for application developers
to write custom TypeConverter implementations that can
convert strings to objects.
Note that this is recommended for simple objects only.
Configure more complex objects by setting properties to references
to other objects.
-->
<xsd:element name="value" type="valueObject"/>
<!--
Contains a string representation of an expression.
-->
<xsd:element name="expression" type="expression"/>
<!--
Denotes a .NET null value. Necessary because an empty "value" tag
will resolve to an empty String, which will not be resolved to a
null value unless a special TypeConverter does so.
-->
<xsd:element name="null" />
<xsd:any namespace="##other" processContents="strict" />
</xsd:choice>
</xsd:sequence>
</xsd:group>
<xsd:complexType name="objectNameValues">
<xsd:sequence>
<!--
The "value" attribute is the string value of the property. The "key"
attribute is the name of the property.
-->
<xsd:element name="add" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType mixed="true">
<xsd:attribute name="key" type="nonNullString" use="required"/>
<xsd:attribute name="value" use="required" type="xsd:string"/>
<xsd:attribute name="delimiters" use="optional" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="merge" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="importElement">
<xsd:annotation>
<xsd:documentation>Import an external file containing object definitions into this file.</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="resource" type="nonNullString" use="required"/>
</xsd:complexType>
<xsd:complexType name="aliasElement">
<xsd:annotation>
<xsd:documentation>Defines an additional alias name for an object definition.</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="name" type="nonNullString" use="required"/>
<xsd:attribute name="alias" type="nonNullString" use="required"/>
</xsd:complexType>
<xsd:complexType name="objectMap">
<xsd:sequence>
<xsd:element type="mapEntryElement" name="entry" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="key-type" type="nonNullString" use="optional"/>
<xsd:attribute name="value-type" type="nonNullString" use="optional"/>
<xsd:attribute name="merge" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="mapEntryElement">
<xsd:sequence>
<xsd:element type="mapKeyElement" name="key" minOccurs="0" maxOccurs="1"/>
<xsd:group ref="objectList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="key" type="nonNullString" use="optional"/>
<xsd:attribute name="value" type="nonNullString" use="optional"/>
<xsd:attribute name="expression" type="nonNullString" use="optional"/>
<xsd:attribute name="key-ref" type="nonNullString" use="optional"/>
<xsd:attribute name="value-ref" type="nonNullString" use="optional"/>
</xsd:complexType>
<xsd:complexType name="mapKeyElement">
<xsd:group ref="objectList" minOccurs="1"/>
</xsd:complexType>
<xsd:complexType name="lookupMethod">
<xsd:attribute name="name" type="nonNullString" use="required"/>
<xsd:attribute name="object" type="nonNullString" use="required"/>
</xsd:complexType>
<xsd:complexType name="constructorArgument">
<xsd:annotation>
<xsd:documentation>Defines constructor argument.</xsd:documentation>
</xsd:annotation>
<xsd:group ref="objectList" minOccurs="0"/>
<!--
The constructor-arg tag can have an optional named parameter attribute,
to specify a named parameter in the constructor argument list.
-->
<xsd:attribute name="name" type="nonNullString" use="optional"/>
<!--
The constructor-arg tag can have an optional index attribute,
to specify the exact index in the constructor argument list. Only needed
to avoid ambiguities, e.g. in case of 2 arguments of the same type.
-->
<xsd:attribute name="index" type="nonNullString" use="optional"/>
<!--
The constructor-arg tag can have an optional type attribute,
to specify the exact type of the constructor argument. Only needed
to avoid ambiguities, e.g. in case of 2 single argument constructors
that can both be converted from a String.
-->
<xsd:attribute name="type" type="nonNullString" use="optional"/>
<xsd:attribute name="value" type="nonNullString" use="optional"/>
<xsd:attribute name="expression" type="nonNullString" use="optional"/>
<xsd:attribute name="ref" type="nonNullString" use="optional"/>
</xsd:complexType>
<xsd:complexType name="property">
<xsd:annotation>
<xsd:documentation>Defines property.</xsd:documentation>
</xsd:annotation>
<xsd:group ref="objectList" minOccurs="0"/>
<!-- The property name attribute is the name of the objects property. -->
<xsd:attribute name="name" type="nonNullString" use="required"/>
<xsd:attribute name="value" type="nonNullString" use="optional"/>
<xsd:attribute name="expression" type="nonNullString" use="optional"/>
<xsd:attribute name="ref" type="nonNullString" use="optional"/>
</xsd:complexType>
<xsd:complexType name="metaType">
<xsd:attribute name="key" type="nonNullString" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The key name of the metadata attribute being defined.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="value" type="nonNullString" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The value of the metadata attribute being defined (as a simple String).
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="qualifierType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Object definitions can provide qualifiers to match against attributes
on a field or parameter for fine-grained autowire candidate resolution.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="attribute" type="metaType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="type" type="nonNullString" default="Spring.Objects.Factory.Attributes.QualifierAttribute"/>
<xsd:attribute name="value" type="nonNullString" use="optional"/>
</xsd:complexType>
<xsd:complexType name="vanillaObject">
<xsd:annotation>
<xsd:documentation>Defines a single named object.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="description" type="description" minOccurs="0" maxOccurs="1"/>
<!--
Object definitions can specify zero or more constructor arguments.
They correspond to either a specific index of the constructor argument list
or are supposed to be matched generically by type.
This is an alternative to "autowire constructor".
-->
<xsd:element name="constructor-arg" type="constructorArgument" minOccurs="0" maxOccurs="unbounded"/>
<!--
Object definitions can have zero or more properties.
Spring supports primitives, references to other objects in the same or
related factories, lists, dictionaries and properties.
-->
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded"/>
<!--
Object definitions can specify zero or more lookup-methods.
-->
<xsd:element name="lookup-method" type="lookupMethod" minOccurs="0" maxOccurs="unbounded"/>
<!-- Object definitions can have zero or more replaced-methods. -->
<xsd:element name="replaced-method" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="arg-type" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="match" type="nonNullString" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="name" type="nonNullString" use="required"/>
<xsd:attribute name="replacer" type="nonNullString" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- Object definitions can have zero or more subscriptions. -->
<xsd:element name="listener" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ref" type="objectOrClassReference" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<!-- The event(s) the object is interested in. -->
<xsd:attribute name="event" type="nonNullString" use="optional"/>
<!-- The name or name pattern of the method that will handle the event(s). -->
<xsd:attribute name="method" type="nonNullString" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- Object definition can have zero or more meta attribute definitions used for autowiring dependencies -->
<xsd:element name="meta" type="metaType" minOccurs="0" maxOccurs="unbounded"/>
<!-- Object definition can have zero or more qualifier definition used for autowiring dependencies -->
<xsd:element name="qualifier" type="qualifierType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<!--
Objects can be identified by an id, to enable reference checking.
There are constraints on a valid XML id: if you want to reference your object
in .NET code using a name that's illegal as an XML id, use the optional
"name" attribute. If neither given, the object type name is used as id.
-->
<xsd:attribute name="id" type="xsd:ID" use="optional"/>
<!--
Optional. Can be used to create one or more aliases illegal in an id.
Multiple aliases can be separated by any number of spaces or commas.
-->
<xsd:attribute name="name" type="nonNullString" use="optional"/>
<!--
Each object definition must specify the full, assembly qualified of the type,
or the name of the parent object from which the type can be worked out.
Note that a child object definition that references a parent will just
add respectively override property values and be able to change the
singleton status. It will inherit all of the parent's other parameters
like lazy initialization or autowire settings.
-->
<xsd:attribute name="type" type="nonNullString" use="optional"/>
<xsd:attribute name="parent" type="nonNullString" use="optional"/>
<!--
Is this object "abstract", i.e. not meant to be instantiated itself but
rather just serving as parent for concrete child object definitions?
Default is false. Specify true to tell the object factory to not try to
instantiate that particular object in any case.
-->
<xsd:attribute name="abstract" type="xsd:boolean" use="optional" default="false"/>
<!--
Is this object a "singleton" (one shared instance, which will
be returned by all calls to GetObject() with the id),
or a "prototype" (independent instance resulting from each call to
getObject(). Default is singleton.
Singletons are most commonly used, and are ideal for multi-threaded
service objects.
-->
<xsd:attribute name="singleton" type="xsd:boolean" use="optional" default="true"/>
<!--
Optional attribute controlling the scope of singleton instances. It is
only applicable to ASP.Net web applications and it has no effect on prototype
objects. Applications other than ASP.Net web applications simply ignore this attribute.
It has 3 possible values:
1. "application"
Default object scope. Objects defined with application scope will behave like
traditional singleton objects. Same instance will be returned from every call
to IApplicationContext.GetObject()
2. "session"
Objects with this scope will be stored within user's HTTP session. Session scope
is typically used for objects such as shopping cart, user profile, etc.
3. "request"
Object with this scope will be initialized for each HTTP request, but unlike with prototype
objects, same instance will be returned from all calls to IApplicationContext.GetObject()
within the same HTTP request. For example, if one ASP page forwards request to another using
Server.Transfer method, they can easily share the state by configuring dependency to the same
request-scoped object.
-->
<xsd:attribute name="scope" use="optional" default="application">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="application"/>
<xsd:enumeration value="session"/>
<xsd:enumeration value="request"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<!--
Is this object to be lazily initialized?
If false, it will get instantiated on startup by object factories
that perform eager initialization of singletons.
-->
<xsd:attribute name="lazy-init" use="optional" default="default">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="true"/>
<xsd:enumeration value="false"/>
<xsd:enumeration value="default"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<!--
Optional attribute controlling whether to "autowire" object properties.
This is an automagical process in which object references don't need to be coded
explicitly in the XML object definition file, but Spring works out dependencies.
There are 5 modes:
1. "no"
The traditional Spring default. No automagical wiring. Object references
must be defined in the XML file via the <ref> element. We recommend this
in most cases as it makes documentation more explicit.
2. "byName"
Autowiring by property name. If a object of class Cat exposes a dog property,
Spring will try to set this to the value of the object "dog" in the current factory.
3. "byType"
Autowiring if there is exactly one object of the property type in the object factory.
If there is more than one, a fatal error is raised, and you can't use byType
autowiring for that object. If there is none, nothing special happens - use
dependency-check="objects" to raise an error in that case.
4. "constructor"
Analogous to "byType" for constructor arguments. If there isn't exactly one object
of the constructor argument type in the object factory, a fatal error is raised.
5. "autodetect"
Chooses "constructor" or "byType" through introspection of the object class.
If a default constructor is found, "byType" gets applied.
The latter two are similar to PicoContainer and make object factories simple to
configure for small namespaces, but doesn't work as well as standard Spring
behaviour for bigger applications.
Note that explicit dependencies, i.e. "property" and "constructor-arg" elements,
always override autowiring. Autowire behaviour can be combined with dependency
checking, which will be performed after all autowiring has been completed.
-->
<xsd:attribute name="autowire" use="optional" default="default">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="no"/>
<xsd:enumeration value="byName"/>
<xsd:enumeration value="byType"/>
<xsd:enumeration value="constructor"/>
<xsd:enumeration value="autodetect"/>
<xsd:enumeration value="default"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<!--
Is this object the rpimary object if type resolving during Autowiring
-->
<xsd:attribute name="primary" type="xsd:boolean" use="optional" default="false"/>
<!--
Optional attribute controlling whether to check whether all this
objects dependencies, expressed in its properties, are satisfied.
Default is no dependency checking.
"simple" type dependency checking includes primitives and String
"object" includes collaborators (other objects in the factory)
"all" includes both types of dependency checking
-->
<xsd:attribute name="dependency-check" use="optional" default="default">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="none"/>
<xsd:enumeration value="objects"/>
<xsd:enumeration value="simple"/>
<xsd:enumeration value="all"/>
<xsd:enumeration value="default"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<!--
The names of the objects that this object depends on being initialized.
The object factory will guarantee that these objects get initialized before.
Note that dependencies are normally expressed through object properties or
constructor arguments. This property should just be necessary for other kinds
of dependencies like statics (*ugh*) or database preparation on startup.
-->
<xsd:attribute name="depends-on" type="nonNullString" use="optional"/>
<!--
Optional attribute for the name of the custom initialization method
to invoke after setting object properties. The method must have no arguments,
but may throw any exception.
-->
<xsd:attribute name="init-method" type="nonNullString" use="optional"/>
<!--
Optional attribute for the name of the custom destroy method to invoke
on object factory shutdown. The method must have no arguments,
but may throw any exception. Note: Only invoked on singleton objects!
-->
<xsd:attribute name="destroy-method" type="nonNullString" use="optional"/>
<xsd:attribute name="factory-method" type="nonNullString" use="optional"/>
<xsd:attribute name="factory-object" type="nonNullString" use="optional"/>
</xsd:complexType>
<xsd:element name="objects">
<xsd:annotation>
<xsd:documentation>The document root. At least one object definition is required.</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="description" type="description" minOccurs="0" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="import" type="importElement"/>
<xsd:element name="alias" type="aliasElement"/>
<xsd:element name="object" type="vanillaObject"/>
<xsd:any namespace="##other" processContents="strict"/>
</xsd:choice>
</xsd:sequence>
<!--
Default values for all object definitions. Can be overridden at
the "object" level. See those attribute definitions for details.
-->
<xsd:attribute name="default-lazy-init" type="xsd:boolean" use="optional" default="false"/>
<xsd:attribute name="default-merge" type="xsd:boolean" use="optional" default="false"/>
<xsd:attribute name="default-dependency-check" use="optional" default="none">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="none"/>
<xsd:enumeration value="objects"/>
<xsd:enumeration value="simple"/>
<xsd:enumeration value="all"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="default-autowire" use="optional" default="no">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="no"/>
<xsd:enumeration value="byName"/>
<xsd:enumeration value="byType"/>
<xsd:enumeration value="constructor"/>
<xsd:enumeration value="autodetect"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<!--This file is auto-generated by the XML Schema Designer. It holds layout information for components on the designer surface.-->
<XSDDesignerLayout Style="LeftRight" layoutVersion="2" viewPortLeft="0" viewPortTop="0" zoom="100">
<identifiedType_XmlComplexType left="1317" top="167061" width="5292" height="3757" selected="0" zOrder="8" index="0" expanded="1" />
<nonNullString_XmlSimpleType left="1317" top="1254" width="5292" height="3625" selected="0" zOrder="5" index="1" expanded="1" />
<description_XmlSimpleType left="1317" top="5387" width="5292" height="3625" selected="0" zOrder="6" index="2" expanded="1" />
<valueObject_XmlComplexType left="1317" top="9520" width="5292" height="3625" selected="0" zOrder="7" index="3" expanded="1" />
<expression_XmlComplexType left="1317" top="13653" width="5292" height="3625" selected="0" zOrder="9" index="4" expanded="1">
<property_XmlElement left="7243" top="13653" width="5292" height="3625" selected="0" zOrder="10" index="0" expanded="0" />
</expression_XmlComplexType>
<objectReference_XmlComplexType left="1317" top="17786" width="5292" height="3757" selected="0" zOrder="12" index="5" expanded="1" />
<objectOrClassReference_XmlComplexType left="1317" top="22051" width="5292" height="3757" selected="0" zOrder="13" index="6" expanded="1" />
<objectList_XmlGroup left="1317" top="43376" width="5292" height="3757" selected="0" zOrder="14" index="7" expanded="1">
<_x0028_group1_x0029__XmlChoice left="7243" top="43376" width="5292" height="3757" selected="0" zOrder="15" index="1" expanded="1">
<object_XmlElement left="13169" top="26316" width="5292" height="3757" selected="0" zOrder="17" index="0" expanded="0" />
<ref_XmlElement left="13169" top="30581" width="5292" height="3757" selected="0" zOrder="19" index="1" expanded="0" />
<idref_XmlElement left="13169" top="34846" width="5292" height="3757" selected="0" zOrder="21" index="2" expanded="0" />
<list_XmlElement left="13169" top="39111" width="5292" height="3757" selected="0" zOrder="23" index="3" expanded="1">
<_x0028_group1_x0029__XmlChoice left="19095" top="39111" width="5292" height="3757" selected="0" zOrder="25" index="1" expanded="0" />
</list_XmlElement>
<set_XmlElement left="13169" top="43376" width="5292" height="3757" selected="0" zOrder="27" index="4" expanded="1">
<_x0028_group1_x0029__XmlChoice left="19095" top="43376" width="5292" height="3757" selected="0" zOrder="29" index="1" expanded="0" />
</set_XmlElement>
<dictionary_XmlElement left="13169" top="47641" width="5292" height="3757" selected="0" zOrder="31" index="5" expanded="0" />
<name-values_XmlElement left="13169" top="51906" width="5292" height="3757" selected="0" zOrder="33" index="6" expanded="0" />
<value_XmlElement left="13169" top="56171" width="5292" height="3757" selected="0" zOrder="35" index="7" expanded="0" />
<expression_XmlElement left="13169" top="60436" width="5292" height="3757" selected="0" zOrder="37" index="8" expanded="0" />
</_x0028_group1_x0029__XmlChoice>
</objectList_XmlGroup>
<objectNameValues_XmlComplexType left="1317" top="64701" width="5292" height="3757" selected="0" zOrder="39" index="8" expanded="1">
<add_XmlElement left="7243" top="64701" width="5292" height="3757" selected="0" zOrder="40" index="0" expanded="1" />
</objectNameValues_XmlComplexType>
<importElement_XmlComplexType left="1317" top="68966" width="5292" height="3757" selected="0" zOrder="42" index="9" expanded="1" />
<aliasElement_XmlComplexType left="1317" top="73231" width="5292" height="3757" selected="0" zOrder="43" index="10" expanded="1" />
<objectMap_XmlComplexType left="1317" top="77496" width="5292" height="3757" selected="0" zOrder="44" index="11" expanded="1">
<entry_XmlElement left="7243" top="77496" width="5292" height="3757" selected="0" zOrder="45" index="0" expanded="0" />
</objectMap_XmlComplexType>
<mapEntryElement_XmlComplexType left="1317" top="83893" width="5292" height="3757" selected="0" zOrder="47" index="12" expanded="1">
<key_XmlElement left="7243" top="81761" width="5292" height="3757" selected="0" zOrder="48" index="0" expanded="0" />
<ref_x003D_objectList_XmlGroup left="7243" top="86026" width="5292" height="3757" selected="0" zOrder="50" index="1" expanded="0" />
</mapEntryElement_XmlComplexType>
<mapKeyElement_XmlComplexType left="1317" top="90291" width="5292" height="3757" selected="0" zOrder="52" index="13" expanded="1">
<_x0028_group1_x0029__XmlChoice left="7243" top="90291" width="5292" height="3757" selected="0" zOrder="53" index="1" expanded="0" />
</mapKeyElement_XmlComplexType>
<lookupMethod_XmlComplexType left="1317" top="94556" width="5292" height="3757" selected="0" zOrder="55" index="14" expanded="1" />
<constructorArgument_XmlComplexType left="1317" top="98821" width="5292" height="3757" selected="0" zOrder="56" index="15" expanded="1">
<_x0028_group1_x0029__XmlChoice left="7243" top="98821" width="5292" height="3757" selected="0" zOrder="57" index="1" expanded="0" />
</constructorArgument_XmlComplexType>
<property_XmlComplexType left="1317" top="103086" width="5292" height="3757" selected="0" zOrder="59" index="16" expanded="1">
<_x0028_group1_x0029__XmlChoice left="7243" top="103086" width="5292" height="3757" selected="0" zOrder="60" index="1" expanded="0" />
</property_XmlComplexType>
<vanillaObject_XmlComplexType left="1317" top="123716" width="5292" height="3757" selected="0" zOrder="62" index="17" expanded="1">
<constructor-arg_XmlElement left="7243" top="107351" width="5292" height="3757" selected="0" zOrder="63" index="1" expanded="0" />
<property_XmlElement left="7243" top="111616" width="5292" height="3757" selected="0" zOrder="65" index="2" expanded="0" />
<lookup-method_XmlElement left="7243" top="115881" width="5292" height="3757" selected="0" zOrder="67" index="3" expanded="0" />
<replaced-method_XmlElement left="7243" top="120146" width="5292" height="3757" selected="0" zOrder="69" index="4" expanded="1">
<arg-type_XmlElement left="13169" top="120146" width="5292" height="3757" selected="0" zOrder="71" index="0" expanded="1" />
</replaced-method_XmlElement>
<listener_XmlElement left="7243" top="124411" width="5292" height="3757" selected="0" zOrder="73" index="5" expanded="1">
<ref_XmlElement left="13169" top="124411" width="5292" height="3757" selected="0" zOrder="75" index="0" expanded="0" />
</listener_XmlElement>
<scope_XmlAttribute left="7243" top="130065" width="5292" height="979" selected="0" zOrder="77" index="12" expanded="1">
<_x0028_scope_x0029__XmlSimpleType left="13169" top="128676" width="5292" height="3757" selected="0" zOrder="79" index="0" expanded="1" />
</scope_XmlAttribute>
<lazy-init_XmlAttribute left="7243" top="134330" width="5292" height="979" selected="0" zOrder="81" index="13" expanded="1">
<_x0028_lazy-init_x0029__XmlSimpleType left="13169" top="132941" width="5292" height="3757" selected="0" zOrder="83" index="0" expanded="1" />
</lazy-init_XmlAttribute>
<autowire_XmlAttribute left="7243" top="138595" width="5292" height="979" selected="0" zOrder="85" index="14" expanded="1">
<_x0028_autowire_x0029__XmlSimpleType left="13169" top="137206" width="5292" height="3757" selected="0" zOrder="87" index="0" expanded="1" />
</autowire_XmlAttribute>
<dependency-check_XmlAttribute left="7243" top="142860" width="5292" height="979" selected="0" zOrder="89" index="15" expanded="1">
<_x0028_dependency-check_x0029__XmlSimpleType left="13169" top="141471" width="5292" height="3757" selected="0" zOrder="91" index="0" expanded="1" />
</dependency-check_XmlAttribute>
</vanillaObject_XmlComplexType>
<objects_XmlElement left="1317" top="155704" width="5292" height="3757" selected="0" zOrder="93" index="18" expanded="1">
<_x0028_group1_x0029__XmlChoice left="7243" top="150001" width="5292" height="3757" selected="0" zOrder="94" index="1" expanded="1">
<import_XmlElement left="13169" top="145736" width="5292" height="3757" selected="0" zOrder="96" index="0" expanded="0" />
<alias_XmlElement left="13169" top="150001" width="5292" height="3757" selected="0" zOrder="98" index="1" expanded="0" />
<object_XmlElement left="13169" top="154266" width="5292" height="3757" selected="0" zOrder="100" index="2" expanded="0" />
</_x0028_group1_x0029__XmlChoice>
<default-dependency-check_XmlAttribute left="7243" top="159920" width="5292" height="979" selected="0" zOrder="102" index="3" expanded="1">
<_x0028_default-dependency-check_x0029__XmlSimpleType left="13169" top="158531" width="5292" height="3757" selected="0" zOrder="104" index="0" expanded="1" />
</default-dependency-check_XmlAttribute>
<default-autowire_XmlAttribute left="7243" top="164185" width="5292" height="979" selected="0" zOrder="106" index="4" expanded="1">
<_x0028_default-autowire_x0029__XmlSimpleType left="13169" top="162796" width="5292" height="3757" selected="0" zOrder="108" index="0" expanded="1" />
</default-autowire_XmlAttribute>
</objects_XmlElement>
</XSDDesignerLayout>

View File

@@ -0,0 +1,37 @@
#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;
namespace Spring.Objects
{
/// <summary>
/// Interface to be implemented by bean metadata elements
/// that carry a configuration source object.
/// </summary>
public interface IObjectMetadataElement
{
/// <summary>
/// Return the configuration source <code>Object</code> for this metadata element
/// (may be <code>null</code>).
/// </summary>
Object Source { get; }
}
}

View File

@@ -0,0 +1,95 @@
#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 System.Diagnostics;
using Spring.Util;
namespace Spring.Objects
{
/// <summary>
/// Holder for a key-value style attribute that is part of a bean definition.
/// Keeps track of the definition source in addition to the key-value pair.
/// </summary>
public class ObjectMetadataAttribute : IObjectMetadataElement
{
private readonly string _name;
private readonly object _value;
private object _source;
/// <summary>
/// Create a new AttributeValue instance.
/// </summary>
/// <param name="name">the name of the attribute (never <code>null</code>)</param>
/// <param name="value">the value of the attribute (possibly before type conversion)</param>
public ObjectMetadataAttribute(string name, object value)
{
Trace.Assert(name != null, "Name must not be null");
_name = name;
_value = value;
}
/// <summary>
/// Return the name of the attribute.
/// </summary>
public string Name { get { return _name; } }
/// <summary>
/// Return the value of the attribute.
/// </summary>
public object Value { get { return _value; } }
/// <summary>
/// Set the configuration source <code>Object</code> for this metadata element.
/// <p>The exact type of the object will depend on the configuration mechanism used.</p>
/// </summary>
public object Source { get { return _source; } set { _source = value; } }
public override bool Equals(Object other)
{
if (this == other) {
return true;
}
if (!(other is ObjectMetadataAttribute)) {
return false;
}
var otherMa = (ObjectMetadataAttribute) other;
return (_name.Equals(otherMa._name) &&
ObjectUtils.NullSafeEquals(_value, otherMa._value) &&
ObjectUtils.NullSafeEquals(_source, otherMa._source));
}
public override int GetHashCode()
{
return _name.GetHashCode() * 29 + ObjectUtils.NullSafeHashCode(_value);
}
public override string ToString()
{
return "metadata attribute '" + _name + "'";
}
}
}

View File

@@ -0,0 +1,85 @@
#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 Spring.Core;
namespace Spring.Objects
{
/// <summary>
/// Extension of <see cref="AttributeAccessorSupport"/>,
/// holding attributes as <see cref="IObjectMetadataElement"/> objects in order
/// to keep track of the definition source.
/// </summary>
[Serializable]
public class ObjectMetadataAttributeAccessor : AttributeAccessorSupport, IObjectMetadataElement
{
private object _source;
/// <summary>
/// Set the configuration source <code>object</code> for this metadata element.
/// <p>The exact type of the object will depend on the configuration mechanism used.</p>
/// </summary>
public object Source
{
get { return _source; }
set { _source = value; }
}
/// <summary>
/// Add the given BeanMetadataAttribute to this accessor's set of attributes.
/// </summary>
/// <param name="attribute">The BeanMetadataAttribute object to register</param>
public void AddMetadataAttribute(ObjectMetadataAttribute attribute)
{
base.SetAttribute(attribute.Name, attribute);
}
/// <summary>
/// Look up the given BeanMetadataAttribute in this accessor's set of attributes.
/// </summary>
/// <param name="name">the name of the attribute</param>
/// <returns>the corresponding BeanMetadataAttribute object,
/// or <code>null</code> if no such attribute defined
/// </returns>
public ObjectMetadataAttribute GetMetadataAttribute(string name)
{
return (ObjectMetadataAttribute) base.GetAttribute(name);
}
public override void SetAttribute(string name, object value)
{
base.SetAttribute(name, new ObjectMetadataAttribute(name, value));
}
public override object GetAttribute(string name)
{
var attribute = (ObjectMetadataAttribute) base.GetAttribute(name);
return (attribute != null ? attribute.Value : null);
}
public override object RemoveAttribute(string name)
{
var attribute = (ObjectMetadataAttribute) base.RemoveAttribute(name);
return (attribute != null ? attribute.Value : null);
}
}
}

View File

@@ -278,12 +278,14 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Support\XmlApplicationContextArgs.cs" />
<Compile Include="Core\AttributeAccessorSupport.cs" />
<Compile Include="Core\CannotLoadObjectTypeException.cs" />
<Compile Include="Core\ComposedCriteria.cs" />
<Compile Include="Core\ControlFlowFactory.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Core\Conventions.cs" />
<Compile Include="Core\IAttributeAccessor.cs" />
<Compile Include="Core\IO\EncodedResource.cs" />
<Compile Include="Core\IPriorityOrdered.cs" />
<Compile Include="Core\MethodArgumentsCriteria.cs" />
@@ -676,8 +678,14 @@
<Compile Include="Objects\Factory\Attributes\InitDestroyAttributeObjectPostProcessor.cs" />
<Compile Include="Objects\Factory\Attributes\PostConstructAttribute.cs" />
<Compile Include="Objects\Factory\Attributes\PreDestroyAttribute.cs" />
<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\QualifierAnnotationAutowireCandidateResolver.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\Attributes\ValueAttribute.cs" />
<Compile Include="Objects\Factory\Config\AbstractConfigurer.cs" />
<Compile Include="Objects\Factory\Config\CommandLineArgsVariableSource.cs" />
<Compile Include="Objects\Factory\Config\ConfigSectionVariableSource.cs" />
@@ -711,9 +719,13 @@
<Compile Include="Objects\Factory\Parsing\ObjectDefinitionParsingException.cs" />
<Compile Include="Objects\Factory\Parsing\Problem.cs" />
<Compile Include="Objects\Factory\Parsing\ReaderContext.cs" />
<Compile Include="Objects\Factory\Support\AutowireCandidateQualifier.cs" />
<Compile Include="Objects\Factory\Support\DelegateInvokingFactoryObject.cs" />
<Compile Include="Objects\Factory\Support\IObjectDefinitionRegistryPostProcessor.cs" />
<Compile Include="Objects\Factory\Support\ObjectScope.cs" />
<Compile Include="Objects\IObjectMetadataElement.cs" />
<Compile Include="Objects\ObjectMetadataAttribute.cs" />
<Compile Include="Objects\ObjectMetadataAttributeAccessor.cs" />
<Compile Include="Util\ConstructorInstantiationInfo.cs" />
<Compile Include="Objects\Factory\Support\GenericObjectDefinition.cs" />
<Compile Include="Objects\Factory\Support\IAutowireCandidateResolver.cs" />
@@ -1144,6 +1156,7 @@
<Compile Include="Util\IErrorHandler.cs" />
<Compile Include="Util\IEventExceptionsCollector.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\IStringValueResolver.cs" />
<Compile Include="Util\ITextPosition.cs" />
<Compile Include="Util\ObjectUtils.cs" />
<Compile Include="Util\ReflectionException.cs" />
@@ -1232,6 +1245,7 @@
</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Objects\Factory\Xml\spring-objects-1.3.xsd" />
<EmbeddedResource Include="Objects\Factory\Xml\spring-objects-2.0.xsd" />
<None Include="Spring.Core.build" />
<EmbeddedResource Include="Validation\Config\spring-validation-1.3.xsd" />
<EmbeddedResource Include="Validation\Config\spring-validation-1.1.xsd" />

View File

@@ -280,12 +280,14 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Support\XmlApplicationContextArgs.cs" />
<Compile Include="Core\AttributeAccessorSupport.cs" />
<Compile Include="Core\CannotLoadObjectTypeException.cs" />
<Compile Include="Core\ComposedCriteria.cs" />
<Compile Include="Core\ControlFlowFactory.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Core\Conventions.cs" />
<Compile Include="Core\IAttributeAccessor.cs" />
<Compile Include="Core\IO\EncodedResource.cs" />
<Compile Include="Core\IPriorityOrdered.cs" />
<Compile Include="Core\MethodArgumentsCriteria.cs" />
@@ -678,8 +680,14 @@
<Compile Include="Objects\Factory\Attributes\InitDestroyAttributeObjectPostProcessor.cs" />
<Compile Include="Objects\Factory\Attributes\PostConstructAttribute.cs" />
<Compile Include="Objects\Factory\Attributes\PreDestroyAttribute.cs" />
<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\QualifierAnnotationAutowireCandidateResolver.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\Attributes\ValueAttribute.cs" />
<Compile Include="Objects\Factory\Config\AbstractConfigurer.cs" />
<Compile Include="Objects\Factory\Config\CommandLineArgsVariableSource.cs" />
<Compile Include="Objects\Factory\Config\ConfigSectionVariableSource.cs" />
@@ -713,9 +721,13 @@
<Compile Include="Objects\Factory\Parsing\ObjectDefinitionParsingException.cs" />
<Compile Include="Objects\Factory\Parsing\Problem.cs" />
<Compile Include="Objects\Factory\Parsing\ReaderContext.cs" />
<Compile Include="Objects\Factory\Support\AutowireCandidateQualifier.cs" />
<Compile Include="Objects\Factory\Support\DelegateInvokingFactoryObject.cs" />
<Compile Include="Objects\Factory\Support\IObjectDefinitionRegistryPostProcessor.cs" />
<Compile Include="Objects\Factory\Support\ObjectScope.cs" />
<Compile Include="Objects\IObjectMetadataElement.cs" />
<Compile Include="Objects\ObjectMetadataAttribute.cs" />
<Compile Include="Objects\ObjectMetadataAttributeAccessor.cs" />
<Compile Include="Stereotype\ControllerAttribute.cs" />
<Compile Include="Util\ConstructorInstantiationInfo.cs" />
<Compile Include="Objects\Factory\Support\GenericObjectDefinition.cs" />
@@ -1146,6 +1158,7 @@
<Compile Include="Util\IErrorHandler.cs" />
<Compile Include="Util\IEventExceptionsCollector.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\IStringValueResolver.cs" />
<Compile Include="Util\ITextPosition.cs" />
<Compile Include="Util\ObjectUtils.cs" />
<Compile Include="Util\ReflectionException.cs" />
@@ -1235,6 +1248,9 @@
</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Objects\Factory\Xml\spring-objects-1.3.xsd" />
<EmbeddedResource Include="Objects\Factory\Xml\spring-objects-2.0.xsd">
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="Spring.Core.build" />
<EmbeddedResource Include="Validation\Config\spring-validation-1.3.xsd" />
<EmbeddedResource Include="Validation\Config\spring-validation-1.1.xsd" />

View File

@@ -34,6 +34,7 @@
<resources basedir="." prefix="Spring.Objects.Factory.Xml">
<include name="Objects/Factory/Xml/spring-objects-1.1.xsd" />
<include name="Objects/Factory/Xml/spring-objects-1.3.xsd" />
<include name="Objects/Factory/Xml/spring-objects-2.0.xsd" />
</resources>
<resources basedir="." prefix="Spring.Objects.Factory.Xml">
<include name="Objects/Factory/Xml/spring-tool-1.1.xsd" />

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
namespace Spring.Util
{
@@ -42,5 +43,46 @@ namespace Spring.Util
}
return FindAttribute(type.BaseType, attributeType);
}
/// <summary>
/// Get all attribute properties with values for a specific attribute type
/// </summary>
/// <param name="attribute">attribute to check against</param>
/// <returns>collection of all properties with values</returns>
public static IDictionary<string, object> GetAttributeProperties(Attribute attribute)
{
Type attributeType = attribute.GetType();
IDictionary<string, object> attributes = new Dictionary<string, object>();
foreach(var property in attributeType.GetProperties())
{
object value = property.GetValue(attribute, null);
attributes.Add(property.Name, value);
}
return attributes;
}
/// <summary>
/// Get the default name value of an attribute and a specific property
/// </summary>
/// <param name="attribute">attribute from where to get the default value</param>
/// <param name="propertyName">property to get the default value</param>
/// <returns></returns>
public static object GetDefaultValue(Attribute attribute, string propertyName)
{
Type attributeType = attribute.GetType();
try
{
var property = attributeType.GetProperty(propertyName);
if (property == null)
return null;
var instance = Activator.CreateInstance(attributeType);
return property.GetValue(instance, null);
}
catch (Exception)
{
return null;
}
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Spring.Util
{
/// <summary>
/// Simple strategy interface for resolving a String value.
/// </summary>
public interface IStringValueResolver
{
/// <summary>
/// Resolve the given String value, for example parsing placeholders.
/// </summary>
/// <param name="value">the original String value</param>
/// <returns>the resolved String value</returns>
string ParseAndResolveVariables(string value);
}
}

View File

@@ -412,6 +412,19 @@ namespace Spring.Util
return (o1 == o2 || (o1 != null && o1.Equals(o2)));
}
/// <summary>
/// Return as hash code for the given object; typically the value of
/// <code>{@link Object#hashCode()}</code>. If the object is an array,
/// this method will delegate to any of the <code>nullSafeHashCode</code>
/// methods for arrays in this class. If the object is <code>null</code>,
/// this method returns 0.
/// </summary>
public static int NullSafeHashCode(object o1)
{
return (o1 != null ? o1.GetHashCode() : 0);
}
/// <summary>
/// Returns the first element in the supplied <paramref name="enumerator"/>.
/// </summary>

View File

@@ -0,0 +1,87 @@
#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 NUnit.Framework;
using Spring.Context.Support;
using Spring.Objects.Factory.Attributes.ByType;
using AutowireTestConstructorNormal = Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestConstructorNormal;
using AutowireTestFieldNormal = Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestFieldNormal;
using AutowireTestMethodNormal = Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestMethodNormal;
using AutowireTestPropertyNormal = Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestPropertyNormal;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireByQualifierAttributeTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false,
"assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByQualifierAttributeObjects.xml");
}
[Test]
public void InjectOnField()
{
var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnProperty()
{
var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty");
Assert.That(testObj.Ciao, Is.Not.Null);
Assert.That(testObj.Ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnMethod()
{
var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnConstructor()
{
var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructor");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
}
}

View File

@@ -0,0 +1,87 @@
#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 NUnit.Framework;
using Spring.Context.Support;
using Spring.Objects.Factory.Attributes.ByType;
using AutowireTestConstructorNormal = Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestConstructorNormal;
using AutowireTestFieldNormal = Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestFieldNormal;
using AutowireTestMethodNormal = Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestMethodNormal;
using AutowireTestPropertyNormal = Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestPropertyNormal;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireByQualifierTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false,
"assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByQualifierObjects.xml");
}
[Test]
public void InjectOnField()
{
var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnProperty()
{
var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty");
Assert.That(testObj.Ciao, Is.Not.Null);
Assert.That(testObj.Ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnMethod()
{
var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnConstructor()
{
var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructor");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(testObj.ciao.GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
}
}

View File

@@ -0,0 +1,98 @@
#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.Attributes.ByType;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireByTypeFailTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false,
"assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeFailObjects.xml");
}
[Test]
public void FailFieldInjectionTooManyObjects()
{
Exception ex = null;
try
{
var testObj = (AutowireTestFieldNormal)_applicationContext.GetObject("AutowireTestFieldNormal");
}
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 FailPropertyInjectionTooManyObjects()
{
Exception ex = null;
try
{
var testObj = (AutowireTestPropertyNormal)_applicationContext.GetObject("AutowireTestPropertyNormal");
}
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 FailMethodInjectionTooManyObjects()
{
Exception ex = null;
try
{
var testObj = (AutowireTestMethodNormal)_applicationContext.GetObject("AutowireTestMethodNormal");
}
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 FailConstructorInjectionTooManyObjects()
{
Exception ex = null;
try
{
var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructorNormal");
}
catch (Exception e) { ex = e; }
Assert.That(ex, Is.Not.Null, "Should throw an exception");
Assert.That(ex.Message, Is.StringContaining("Error creating object with name"));
}
}
}

View File

@@ -0,0 +1,82 @@
#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.Attributes.ByType;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireByTypeNormalTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false,
"assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeNormalObjects.xml");
}
[Test]
public void InjectOnField()
{
var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestFieldNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestFieldNormal");
Assert.That(testObj.hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnProperty()
{
var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestPropertyNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestPropertyNormal");
Assert.That(testObj.Hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnMethod()
{
var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethodNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethodNormal");
Assert.That(testObj.hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnConstructor()
{
var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructorNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructorNormal");
Assert.That(testObj.hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
}
}

View File

@@ -0,0 +1,72 @@
#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.Attributes.ByType;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireByTypeNotRequiredTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false,
"assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypeNotRequiredObjects.xml");
}
[Test]
public void InjectOnField()
{
var testObj = (AutowireTestFieldNotRequired) _applicationContext.GetObject("AutowireTestField");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField");
Assert.That(testObj.hello, Is.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
[Test]
public void InjectOnProperty()
{
var testObj = (AutowireTestPropertyNotRequired) _applicationContext.GetObject("AutowireTestProperty");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty");
Assert.That(testObj.Hello, Is.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
[Test]
public void InjectOnMethod()
{
var testObj = (AutowireTestMethodNotRequired) _applicationContext.GetObject("AutowireTestMethod");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod");
Assert.That(testObj.hello, Is.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
}
}

View File

@@ -0,0 +1,82 @@
#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.Attributes.ByType;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireByTypePrimaryTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false,
"assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByTypePrimaryObjects.xml");
}
[Test]
public void InjectOnField()
{
var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestFieldNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestFieldNormal");
Assert.That(testObj.hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnProperty()
{
var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestPropertyNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestPropertyNormal");
Assert.That(testObj.Hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnMethod()
{
var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethodNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethodNormal");
Assert.That(testObj.hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
[Test]
public void InjectOnConstructor()
{
var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructorNormal");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructorNormal");
Assert.That(testObj.hello, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
}
}

View File

@@ -0,0 +1,96 @@
#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.Collections.Specialized;
using NUnit.Framework;
using Spring.Context;
using Spring.Context.Support;
using Spring.Objects.Factory.Attributes.ByValue;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireByValueTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false, "assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByValueObjects.xml");
ContextRegistry.RegisterContext(_applicationContext);
}
[TearDown]
public void Dispose()
{
ContextRegistry.Clear();
}
[Test]
public void InjectOnField()
{
var testObj = (AutowireTestFieldNormal) _applicationContext.GetObject("AutowireTestField");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestField");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
[Test]
public void InjectOnProperty()
{
var testObj = (AutowireTestPropertyNormal) _applicationContext.GetObject("AutowireTestProperty");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestProperty");
Assert.That(testObj.Ciao, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
[Test]
public void InjectOnMethod()
{
var testObj = (AutowireTestMethodNormal) _applicationContext.GetObject("AutowireTestMethod");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestMethod");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
[Test]
public void InjectOnConstructor()
{
var testObj = (AutowireTestConstructorNormal)_applicationContext.GetObject("AutowireTestConstructor");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestConstructor");
Assert.That(testObj.ciao, Is.Not.Null);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(0));
}
[Test]
public void InjectPropertyPlaceholderValue()
{
var testObj = (AutowireTestPropertyPlaceHolder)_applicationContext.GetObject("AutowireTestPropertyPlaceHolder");
Assert.That(testObj.greeting, Is.EqualTo("ciao"));
}
}
}

View File

@@ -0,0 +1,106 @@
#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.Attributes.ByType;
using Spring.Objects.Factory.Attributes.Collections;
namespace Spring.Objects.Factory.Attributes
{
[TestFixture]
public class AutowireCollectionTests
{
private XmlApplicationContext _applicationContext;
[SetUp]
public void Setup()
{
_applicationContext = new XmlApplicationContext(false,
"assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/CollectionObjects.xml");
}
[Test]
public void InjectIntoList()
{
var testObj = (AutowireTestList)_applicationContext.GetObject("AutowireTestList");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestList");
Assert.That(testObj.foos, Is.Not.Null);
Assert.That(testObj.foos.Count, Is.EqualTo(2));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2));
}
[Test]
public void InjectIntoSet()
{
var testObj = (AutowireTestSet)_applicationContext.GetObject("AutowireTestSet");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestSet");
Assert.That(testObj.foos, Is.Not.Null);
Assert.That(testObj.foos.Count, Is.EqualTo(2));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2));
}
[Test]
public void InjectIntoDictionary()
{
var testObj = (AutowireTestDictionary)_applicationContext.GetObject("AutowireTestDictionary");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestDictionary");
Assert.That(testObj.foos, Is.Not.Null);
Assert.That(testObj.foos.Count, Is.EqualTo(2));
Assert.That(testObj.foos.ContainsKey("HelloFoo"), Is.True);
Assert.That(testObj.foos.ContainsKey("CiaoFoo"), Is.True);
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(2));
}
[Test]
public void InjectIntoDictionaryFail()
{
Exception ex = null;
try
{
var testObj = (AutowireTestDictionaryFail)_applicationContext.GetObject("AutowireTestDictionaryFail");
}
catch (Exception e)
{
ex = e;
}
Assert.That(ex, Is.Not.Null);
Assert.That(ex.InnerException.InnerException.Message.Contains("first generic to be a string"), Is.True);
}
[Test]
public void InjectIntoListWithQualifier()
{
var testObj = (AutowireTestQualifier)_applicationContext.GetObject("AutowireTestQualifier");
var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("AutowireTestQualifier");
Assert.That(testObj.foos, Is.Not.Null);
Assert.That(testObj.foos.Count, Is.EqualTo(1));
Assert.That(testObj.foos[0].GetType(), Is.EqualTo(typeof(CiaoFoo)));
Assert.That(objectDefinition.DependsOn.Count, Is.EqualTo(1));
}
}
}

View File

@@ -0,0 +1,252 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Spring.Objects.Factory.Attributes.ByType;
namespace Spring.Objects.Factory.Attributes.ByType
{
public interface IFoo
{
string Say();
}
public class HelloFoo : IFoo
{
public string Say()
{
return "hello";
}
}
public class CiaoFoo : IFoo
{
public string Say()
{
return "ciao";
}
}
public class AutowireTestFieldNormal
{
[Autowired]
public IFoo hello;
}
public class AutowireTestPropertyNormal
{
[Autowired]
public IFoo Hello { get; set; }
}
public class AutowireTestMethodNormal
{
public IFoo hello;
[Autowired]
private void Prepare(IFoo hello)
{
this.hello = hello;
}
}
public class AutowireTestConstructorNormal
{
public IFoo hello;
[Autowired]
public AutowireTestConstructorNormal(IFoo hello)
{
this.hello = hello;
}
}
public class AutowireTestFieldNotRequired
{
[Autowired(Required = false)]
public IFoo hello;
}
public class AutowireTestPropertyNotRequired
{
[Autowired(Required = false)]
public IFoo Hello { get; set; }
}
public class AutowireTestMethodNotRequired
{
public IFoo hello;
[Autowired(Required = false)]
private void Prepare(IFoo hello)
{
this.hello = hello;
}
}
}
namespace Spring.Objects.Factory.Attributes.ByQualifier
{
public class AutowireTestFieldNormal
{
[Autowired]
[Qualifier("ciao")]
public IFoo ciao;
}
public class AutowireTestPropertyNormal
{
[Autowired]
[Qualifier("ciao")]
public IFoo Ciao { get; set; }
}
public class AutowireTestMethodNormal
{
public IFoo ciao;
[Autowired]
private void Prepare([Qualifier("ciao")] IFoo ciao)
{
this.ciao = ciao;
}
}
public class AutowireTestConstructorNormal
{
public IFoo ciao;
[Autowired]
public AutowireTestConstructorNormal([Qualifier("ciao")] IFoo ciao)
{
this.ciao = ciao;
}
}
}
namespace Spring.Objects.Factory.Attributes.ByQualifierAttribute
{
public class DialectAttribute : QualifierAttribute
{
private string _language = "";
public string Language { get { return _language; } set { _language = value; } }
}
public class AutowireTestFieldNormal
{
[Autowired]
[Dialect(Language = "Italian")]
public IFoo ciao;
}
public class AutowireTestPropertyNormal
{
[Autowired]
[Dialect(Language = "Italian")]
public IFoo Ciao { get; set; }
}
public class AutowireTestMethodNormal
{
public IFoo ciao;
[Autowired]
private void Prepare([Dialect(Language = "Italian")] IFoo ciao)
{
this.ciao = ciao;
}
}
public class AutowireTestConstructorNormal
{
public IFoo ciao;
[Autowired]
public AutowireTestConstructorNormal([Dialect(Language = "Italian")] IFoo ciao)
{
this.ciao = ciao;
}
}
}
namespace Spring.Objects.Factory.Attributes.ByValue
{
public class AutowireTestFieldNormal
{
[Value("@(CiaoFoo)")]
public IFoo ciao;
}
public class AutowireTestPropertyNormal
{
[Value("@(CiaoFoo)")]
public IFoo Ciao { get; set; }
}
public class AutowireTestMethodNormal
{
public IFoo ciao;
[Autowired]
private void Prepare([Value("@(CiaoFoo)")] IFoo ciao)
{
this.ciao = ciao;
}
}
public class AutowireTestConstructorNormal
{
public IFoo ciao;
[Autowired]
public AutowireTestConstructorNormal([Value("@(CiaoFoo)")] IFoo ciao)
{
this.ciao = ciao;
}
}
public class AutowireTestPropertyPlaceHolder
{
[Value("${greeting}")]
public string greeting;
}
}
namespace Spring.Objects.Factory.Attributes.Collections
{
public class AutowireTestList
{
[Autowired]
public IList<IFoo> foos;
}
public class AutowireTestSet
{
[Autowired]
public Spring.Collections.Generic.ISet<IFoo> foos;
}
public class AutowireTestDictionary
{
[Autowired]
public IDictionary<string, IFoo> foos;
}
public class AutowireTestDictionaryFail
{
[Autowired]
public IDictionary<IFoo, IFoo> foos;
}
public class AutowireTestQualifier
{
[Autowired]
[Qualifier("ciao")]
public IList<IFoo> foos;
}
}

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="HelloFoo"
type="Spring.Objects.Factory.Attributes.ByType.HelloFoo, Spring.Core.Tests">
<qualifier type="Spring.Objects.Factory.Attributes.ByQualifierAttribute.DialectAttribute">
<attribute key="Language" value="English" />
</qualifier>
</object>
<object id="CiaoFoo"
type="Spring.Objects.Factory.Attributes.ByType.CiaoFoo, Spring.Core.Tests">
<qualifier type="Spring.Objects.Factory.Attributes.ByQualifierAttribute.DialectAttribute">
<attribute key="Language" value="Italian" />
</qualifier>
</object>
<object id="AutowireTestField"
type="Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestFieldNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestProperty"
type="Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestPropertyNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestMethod"
type="Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestMethodNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestConstructor"
type="Spring.Objects.Factory.Attributes.ByQualifierAttribute.AutowireTestConstructorNormal, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="HelloFoo"
type="Spring.Objects.Factory.Attributes.ByType.HelloFoo, Spring.Core.Tests">
<qualifier value="hello" />
</object>
<object id="CiaoFoo"
type="Spring.Objects.Factory.Attributes.ByType.CiaoFoo, Spring.Core.Tests">
<qualifier value="ciao" />
</object>
<object id="AutowireTestField"
type="Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestFieldNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestProperty"
type="Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestPropertyNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestMethod"
type="Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestMethodNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestConstructor"
type="Spring.Objects.Factory.Attributes.ByQualifier.AutowireTestConstructorNormal, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="HelloFoo"
type="Spring.Objects.Factory.Attributes.ByType.HelloFoo, Spring.Core.Tests" />
<object id="CiaoFoo"
type="Spring.Objects.Factory.Attributes.ByType.CiaoFoo, Spring.Core.Tests" />
<object id="AutowireTestFieldNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestFieldNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestPropertyNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestPropertyNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestMethodNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestMethodNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestConstructorNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestConstructorNormal, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="HelloFoo"
type="Spring.Objects.Factory.Attributes.ByType.HelloFoo, Spring.Core.Tests" />
<object id="AutowireTestFieldNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestFieldNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestPropertyNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestPropertyNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestMethodNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestMethodNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestConstructorNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestConstructorNormal, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="AutowireTestField"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestFieldNotRequired, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestProperty"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestPropertyNotRequired, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestMethod"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestMethodNotRequired, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="HelloFoo"
type="Spring.Objects.Factory.Attributes.ByType.HelloFoo, Spring.Core.Tests"
primary="true"/>
<object id="CiaoFoo"
type="Spring.Objects.Factory.Attributes.ByType.CiaoFoo, Spring.Core.Tests" />
<object id="AutowireTestFieldNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestFieldNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestPropertyNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestPropertyNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestMethodNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestMethodNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestConstructorNormal"
type="Spring.Objects.Factory.Attributes.ByType.AutowireTestConstructorNormal, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
</sectionGroup>
<section name="NameValues" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<NameValues>
<add key="greeting" value="ciao"/>
</NameValues>
</configuration>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object id="appPropertyConfigurer" type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
<property name="Location" value="assembly://Spring.Core.Tests/Spring.Objects.Factory.Attributes/ByValueObjects.config" />
<property name="ConfigSections" value="NameValues" />
</object>
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="HelloFoo"
type="Spring.Objects.Factory.Attributes.ByType.HelloFoo, Spring.Core.Tests" />
<object id="CiaoFoo"
type="Spring.Objects.Factory.Attributes.ByType.CiaoFoo, Spring.Core.Tests" />
<object id="AutowireTestField"
type="Spring.Objects.Factory.Attributes.ByValue.AutowireTestFieldNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestProperty"
type="Spring.Objects.Factory.Attributes.ByValue.AutowireTestPropertyNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestMethod"
type="Spring.Objects.Factory.Attributes.ByValue.AutowireTestMethodNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestConstructor"
type="Spring.Objects.Factory.Attributes.ByValue.AutowireTestConstructorNormal, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestPropertyPlaceHolder"
type="Spring.Objects.Factory.Attributes.ByValue.AutowireTestPropertyPlaceHolder, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object type="Spring.Objects.Factory.Attributes.AutowiredAttributeObjectPostProcessor, Spring.Core" />
<object id="HelloFoo"
type="Spring.Objects.Factory.Attributes.ByType.HelloFoo, Spring.Core.Tests">
<qualifier value="hello" />
</object>
<object id="CiaoFoo"
type="Spring.Objects.Factory.Attributes.ByType.CiaoFoo, Spring.Core.Tests">
<qualifier value="ciao" />
</object>
<object id="AutowireTestList"
type="Spring.Objects.Factory.Attributes.Collections.AutowireTestList, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestSet"
type="Spring.Objects.Factory.Attributes.Collections.AutowireTestSet, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestDictionary"
type="Spring.Objects.Factory.Attributes.Collections.AutowireTestDictionary, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestDictionaryFail"
type="Spring.Objects.Factory.Attributes.Collections.AutowireTestDictionaryFail, Spring.Core.Tests"
lazy-init="true" />
<object id="AutowireTestQualifier"
type="Spring.Objects.Factory.Attributes.Collections.AutowireTestQualifier, Spring.Core.Tests"
lazy-init="true" />
</objects>

View File

@@ -150,6 +150,7 @@ namespace Spring.Objects.Factory.Config
IConfigurableListableObjectFactory mock = (IConfigurableListableObjectFactory) mocks.CreateMock(typeof(IConfigurableListableObjectFactory));
Expect.Call(mock.GetObjectDefinitionNames()).Return(new string [] {defName});
Expect.Call(mock.GetObjectDefinition(defName)).Return(def);
Expect.Call(delegate { mock.AddEmbeddedValueResolver(null); }).IgnoreArguments();
mocks.ReplayAll();
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
@@ -422,6 +423,7 @@ namespace Spring.Objects.Factory.Config
IConfigurableListableObjectFactory mock = (IConfigurableListableObjectFactory) mocks.CreateMock(typeof (IConfigurableListableObjectFactory));
Expect.Call(mock.GetObjectDefinitionNames()).Return(new string[] {"foo"});
Expect.Call(mock.GetObjectDefinition(null)).IgnoreArguments().Return(def);
Expect.Call(delegate { mock.AddEmbeddedValueResolver(null); }).IgnoreArguments();
mocks.ReplayAll();
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
@@ -451,6 +453,7 @@ namespace Spring.Objects.Factory.Config
IConfigurableListableObjectFactory mock = (IConfigurableListableObjectFactory) mocks.CreateMock(typeof (IConfigurableListableObjectFactory));
Expect.Call(mock.GetObjectDefinitionNames()).Return(new string[] {"foo"});
Expect.Call(mock.GetObjectDefinition(null)).IgnoreArguments().Return(def);
Expect.Call(delegate { mock.AddEmbeddedValueResolver(null); }).IgnoreArguments();
mocks.ReplayAll();
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
@@ -548,6 +551,7 @@ namespace Spring.Objects.Factory.Config
IConfigurableListableObjectFactory mock = (IConfigurableListableObjectFactory) mocks.CreateMock(typeof(IConfigurableListableObjectFactory));
Expect.Call(mock.GetObjectDefinitionNames()).Return(new string [] {defName});
Expect.Call(mock.GetObjectDefinition(defName)).Return(def);
Expect.Call(delegate { mock.AddEmbeddedValueResolver(null); }).IgnoreArguments();
mocks.ReplayAll();
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();

View File

@@ -73,6 +73,11 @@ namespace Spring.Objects.Factory
get { return false; }
}
public bool IsPrimary
{
get { return false; }
}
public string ParentName
{
get { return null; }

View File

@@ -317,6 +317,15 @@
<Compile Include="HookableContextHandler.cs" />
<Compile Include="Objects\ExpressionTestObject.cs" />
<Compile Include="Objects\Factory\Attributes\PostConstructAttributeTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypeNormalTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypeFailTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireTestObjects.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypePrimaryTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypeNotRequiredTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByQualifierTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByQualifierAttributeTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByValueTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireCollectionTests.cs" />
<Compile Include="Objects\Factory\Attributes\MyRequiredAttribute.cs" />
<Compile Include="Objects\Factory\Attributes\PreDestroyAttributeTests.cs" />
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessorTests.cs" />
@@ -867,6 +876,15 @@
<EmbeddedResource Include="Objects\Factory\Attributes\RequiredWithThreeRequiredPropertiesOmitted.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\RequiredWithAllRequiredPropertiesProvided.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\RequiredWithCustomAttribute.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypeNormalObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypeFailObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypePrimaryObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypeNotRequiredObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByQualifierObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByQualifierAttributeObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByValueObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByValueObjects.config" />
<EmbeddedResource Include="Objects\Factory\Attributes\CollectionObjects.xml" />
<Content Include="Spring.Core.Tests.dll.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

View File

@@ -319,6 +319,15 @@
<Compile Include="HookableContextHandler.cs" />
<Compile Include="Objects\ExpressionTestObject.cs" />
<Compile Include="Objects\Factory\Attributes\PostConstructAttributeTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypeNormalTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypeFailTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireTestObjects.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypePrimaryTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByTypeNotRequiredTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByQualifierTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByQualifierAttributeTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireByValueTests.cs" />
<Compile Include="Objects\Factory\Attributes\AutowireCollectionTests.cs" />
<Compile Include="Objects\Factory\Attributes\MyRequiredAttribute.cs" />
<Compile Include="Objects\Factory\Attributes\PreDestroyAttributeTests.cs" />
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessorTests.cs" />
@@ -870,6 +879,15 @@
<EmbeddedResource Include="Objects\Factory\Attributes\RequiredWithThreeRequiredPropertiesOmitted.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\RequiredWithAllRequiredPropertiesProvided.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\RequiredWithCustomAttribute.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypeNormalObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypeFailObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypePrimaryObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByTypeNotRequiredObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByQualifierObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByQualifierAttributeObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByValueObjects.xml" />
<EmbeddedResource Include="Objects\Factory\Attributes\ByValueObjects.config" />
<EmbeddedResource Include="Objects\Factory\Attributes\CollectionObjects.xml" />
<Content Include="Spring.Core.Tests.dll.config" />
<EmbeddedResource Include="Resources\Spring.Context.Tests.de-AT.resx" />
<EmbeddedResource Include="Resources\Spring.Context.Tests.de.resx" />

View File

@@ -40,6 +40,7 @@
<include name="**/*.vb" />
<include name="**/*.properties" />
<include name="**/*.xml" />
<include name="**/*.config" />
<!--
<include name="**/SimpleAppContext.xml" />
<include name="**/Factory/Attributes/*.xml" />