SPRNET-881 Add XML configuration option for default-autowire-candidates/autowire-candidate and modify IObjectFactory.GetObject<T>() to return requested object with the use of autowire-candidate filter
This commit is contained in:
@@ -260,6 +260,37 @@ namespace Spring.Objects.Factory
|
||||
#endif
|
||||
object this[string name] { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance (possibly shared or independent) of the given object name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method allows an object factory to be used as a replacement for the
|
||||
/// Singleton or Prototype design pattern.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Note that callers should retain references to returned objects. There is no
|
||||
/// guarantee that this method will be implemented to be efficient. For example,
|
||||
/// it may be synchronized, or may need to run an RDBMS query.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Will ask the parent factory if the object cannot be found in this factory
|
||||
/// instance.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The type of the object to return.</typeparam>
|
||||
/// <returns>The instance of the object.</returns>
|
||||
/// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
|
||||
/// If there's no such object definition.
|
||||
/// </exception>
|
||||
/// <exception cref="Spring.Objects.Factory.ObjectDefinitionStoreException">
|
||||
/// If there is more than a single object of the requested type defined in the factory.
|
||||
/// </exception>
|
||||
/// <exception cref="Spring.Objects.ObjectsException">
|
||||
/// If the object could not be created.
|
||||
/// </exception>
|
||||
T GetObject<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance (possibly shared or independent) of the given object name.
|
||||
/// </summary>
|
||||
|
||||
@@ -814,7 +814,8 @@ namespace Spring.Objects.Factory.Support
|
||||
AutowireMode = other.AutowireMode;
|
||||
ResourceDescription = other.ResourceDescription;
|
||||
IsPrimary = other.IsPrimary;
|
||||
|
||||
IsAutowireCandidate = other.IsAutowireCandidate;
|
||||
|
||||
AbstractObjectDefinition aod = other as AbstractObjectDefinition;
|
||||
if (aod != null)
|
||||
{
|
||||
@@ -846,6 +847,7 @@ namespace Spring.Objects.Factory.Support
|
||||
buffer.Append("; Singleton = ").Append(IsSingleton);
|
||||
buffer.Append("; LazyInit = ").Append(IsLazyInit);
|
||||
buffer.Append("; Autowire = ").Append(AutowireMode);
|
||||
buffer.Append("; Autowire-Candidate = ").Append(IsAutowireCandidate);
|
||||
buffer.Append("; Primary = ").Append(IsPrimary);
|
||||
buffer.Append("; DependencyCheck = ").Append(DependencyCheck);
|
||||
buffer.Append("; InitMethodName = ").Append(InitMethodName);
|
||||
|
||||
@@ -1917,6 +1917,38 @@ namespace Spring.Objects.Factory.Support
|
||||
return GetObjectInternal(name, null, null, false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance (possibly shared or independent) of the given object name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method allows an object factory to be used as a replacement for the
|
||||
/// Singleton or Prototype design pattern.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Note that callers should retain references to returned objects. There is no
|
||||
/// guarantee that this method will be implemented to be efficient. For example,
|
||||
/// it may be synchronized, or may need to run an RDBMS query.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Will ask the parent factory if the object cannot be found in this factory
|
||||
/// instance.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The type of the object to return.</typeparam>
|
||||
/// <returns>The instance of the object.</returns>
|
||||
/// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
|
||||
/// If there's no such object definition.
|
||||
/// </exception>
|
||||
/// <exception cref="Spring.Objects.Factory.ObjectDefinitionStoreException">
|
||||
/// If there is more than a single object of the requested type defined in the factory.
|
||||
/// </exception>
|
||||
/// <exception cref="Spring.Objects.ObjectsException">
|
||||
/// If the object could not be created.
|
||||
/// </exception>
|
||||
public abstract T GetObject<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance (possibly shared or independent) of the given object name.
|
||||
/// </summary>
|
||||
|
||||
@@ -949,20 +949,41 @@ namespace Spring.Objects.Factory.Support
|
||||
/// <exception cref="Spring.Objects.ObjectsException">
|
||||
/// If the object could not be created.
|
||||
/// </exception>
|
||||
public T GetObject<T>()
|
||||
public override T GetObject<T>()
|
||||
{
|
||||
IList<string> objectNamesForType = GetObjectNamesForType(typeof(T));
|
||||
|
||||
if (objectNamesForType.Count > 1)
|
||||
{
|
||||
IList<string> autowireCandidates = new List<string>();
|
||||
foreach (var objectName in objectNamesForType)
|
||||
{
|
||||
if (GetObjectDefinition(objectName).IsAutowireCandidate)
|
||||
autowireCandidates.Add(objectName);
|
||||
|
||||
}
|
||||
if (autowireCandidates.Count > 0)
|
||||
objectNamesForType = autowireCandidates;
|
||||
}
|
||||
|
||||
if ((objectNamesForType == null) || (objectNamesForType.Count == 0))
|
||||
{
|
||||
throw new NoSuchObjectDefinitionException(typeof(T).FullName, "Requested Type not Defined in the Context.");
|
||||
}
|
||||
|
||||
if (objectNamesForType.Count > 1)
|
||||
if (objectNamesForType.Count == 1)
|
||||
{
|
||||
throw new ObjectDefinitionStoreException(string.Format("More than one definition for {0} found in the Context.", typeof(T).FullName));
|
||||
return (T)GetObject(objectNamesForType[0]);
|
||||
}
|
||||
else if (objectNamesForType.Count == 0 && ParentObjectFactory != null)
|
||||
{
|
||||
return ParentObjectFactory.GetObject<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NoSuchObjectDefinitionException(typeof(T), "expected single bean but found " +
|
||||
objectNamesForType.Count + ": " + StringUtils.ArrayToCommaDelimitedString(objectNamesForType));
|
||||
}
|
||||
|
||||
return (T)GetObject(objectNamesForType[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -336,6 +336,28 @@ namespace Spring.Objects.Factory.Support
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the autowire candidate value for this definition.
|
||||
/// </summary>
|
||||
/// <param name="autowireCandidate">The autowire candidate value</param>
|
||||
/// <returns></returns>
|
||||
public ObjectDefinitionBuilder SetAutowireCandidate(bool autowireCandidate)
|
||||
{
|
||||
objectDefinition.IsAutowireCandidate = autowireCandidate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the primary value for this definition.
|
||||
/// </summary>
|
||||
/// <param name="primary">If object is primary</param>
|
||||
/// <returns></returns>
|
||||
public ObjectDefinitionBuilder SetPrimary(bool primary)
|
||||
{
|
||||
objectDefinition.IsPrimary = primary;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the dependency check mode for this definition.
|
||||
/// </summary>
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace Spring.Objects.Factory.Xml
|
||||
private string dependencyCheck;
|
||||
private string lazyInit;
|
||||
private string merge;
|
||||
private string autowireCandidates;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the autowire setting for the document that's currently parsed.
|
||||
@@ -73,5 +74,15 @@ namespace Spring.Objects.Factory.Xml
|
||||
get { return merge; }
|
||||
set { merge = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets autowire candidates for the document that's currently parsed
|
||||
/// </summary>
|
||||
/// <value>The Autowire Candidates</value>
|
||||
public string AutowireCandidates
|
||||
{
|
||||
get { return autowireCandidates; }
|
||||
set { autowireCandidates = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,12 @@ namespace Spring.Objects.Factory.Xml
|
||||
/// </remarks>
|
||||
public const string TrueValue = "true";
|
||||
|
||||
/// <summary>
|
||||
/// Value of a boolean attribute that represents
|
||||
/// <see langword="false"/>.
|
||||
/// </summary>
|
||||
public const string FalseValue = "false";
|
||||
|
||||
/// <summary>
|
||||
/// Signifies that a default value is to be applied.
|
||||
/// </summary>
|
||||
@@ -90,6 +96,11 @@ namespace Spring.Objects.Factory.Xml
|
||||
/// </summary>
|
||||
public const string DefaultAutowireAttribute = "default-autowire";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the default autowire candidates.
|
||||
/// </summary>
|
||||
public const string DefaultAutowireCandidatesAttribute = "default-autowire-candidates";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the default collection merge mode.
|
||||
/// </summary>
|
||||
@@ -586,6 +597,11 @@ namespace Spring.Objects.Factory.Xml
|
||||
/// </summary>
|
||||
public const string AutowireAttribute = "autowire";
|
||||
|
||||
/// <summary>
|
||||
/// The autowiring mode for an individual object definition.
|
||||
/// </summary>
|
||||
public const string AutowireCandidateAttribute = "autowire-candidate";
|
||||
|
||||
/// <summary>
|
||||
/// Attribute element to farther deifne the qualifier of an object
|
||||
/// </summary>
|
||||
|
||||
@@ -175,6 +175,20 @@ namespace Spring.Objects.Factory.Xml
|
||||
|
||||
#endregion
|
||||
|
||||
ddd.AutowireCandidates = GetAttributeValue(root, ObjectDefinitionConstants.DefaultAutowireCandidatesAttribute);
|
||||
|
||||
#region Instrumentation
|
||||
|
||||
if (log.IsDebugEnabled)
|
||||
{
|
||||
log.Debug(
|
||||
string.Format(
|
||||
"Default autowire candidates '{0}'.",
|
||||
ddd.AutowireCandidates));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
defaults = ddd;
|
||||
}
|
||||
|
||||
|
||||
@@ -481,10 +481,24 @@ namespace Spring.Objects.Factory.Xml
|
||||
autowire = childParserContext.ParserHelper.Defaults.Autowire;
|
||||
}
|
||||
od.AutowireMode = GetAutowireMode(autowire);
|
||||
string primary = GetAttributeValue(element, ObjectDefinitionConstants.PrimaryAttribute);
|
||||
if (primary == null)
|
||||
|
||||
string autowireCandidates = GetAttributeValue(element, ObjectDefinitionConstants.AutowireCandidateAttribute);
|
||||
if (string.IsNullOrEmpty(autowireCandidates) || ObjectDefinitionConstants.DefaultValue.Equals(autowireCandidates))
|
||||
{
|
||||
primary = "false";
|
||||
if (!string.IsNullOrEmpty(childParserContext.ParserHelper.Defaults.AutowireCandidates))
|
||||
{
|
||||
string[] patterns = childParserContext.ParserHelper.Defaults.AutowireCandidates.Split(',');
|
||||
od.IsAutowireCandidate = PatternMatchUtils.SimpleMatch(patterns, id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
od.IsAutowireCandidate = ObjectDefinitionConstants.TrueValue.Equals(autowireCandidates);
|
||||
}
|
||||
string primary = GetAttributeValue(element, ObjectDefinitionConstants.PrimaryAttribute);
|
||||
if (string.IsNullOrEmpty(primary))
|
||||
{
|
||||
primary = ObjectDefinitionConstants.FalseValue;
|
||||
}
|
||||
od.IsPrimary = IsTrueStringValue(primary);
|
||||
string initMethodName = GetAttributeValue(element, ObjectDefinitionConstants.InitMethodAttribute);
|
||||
|
||||
@@ -500,10 +500,25 @@
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<!--
|
||||
Is this object the rpimary object if type resolving during Autowiring
|
||||
-->
|
||||
Indicates whether or not this object should be considered when looking
|
||||
for matching candidates to satisfy another object's autowiring requirements.
|
||||
Note that this does not affect explicit references by name, which will get
|
||||
resolved even if the specified bean is not marked as an autowire candidate.
|
||||
-->
|
||||
<xsd:attribute name="autowire-candidate" use="optional" default="default">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="default"/>
|
||||
<xsd:enumeration value="true"/>
|
||||
<xsd:enumeration value="false"/>
|
||||
</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.
|
||||
@@ -553,42 +568,49 @@
|
||||
<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: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:attribute name="default-autowire-candidates" type="xsd:string" use="optional" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
@@ -1608,6 +1608,36 @@ namespace Spring.Objects.Factory
|
||||
Assert.AreEqual(ExpectedAge, child.Age);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetObjectByTypeWithAmbiguity()
|
||||
{
|
||||
DefaultListableObjectFactory lbf = new DefaultListableObjectFactory();
|
||||
RootObjectDefinition bd1 = new RootObjectDefinition(typeof(TestObject));
|
||||
RootObjectDefinition bd2 = new RootObjectDefinition(typeof(TestObject));
|
||||
lbf.RegisterObjectDefinition("bd1", bd1);
|
||||
lbf.RegisterObjectDefinition("bd2", bd2);
|
||||
|
||||
Assert.That(delegate { lbf.GetObject<TestObject>(); }, Throws.Exception.TypeOf<NoSuchObjectDefinitionException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetObjectByTypeFiltersOutNonAutowireCandidates()
|
||||
{
|
||||
DefaultListableObjectFactory lbf = new DefaultListableObjectFactory();
|
||||
RootObjectDefinition bd1 = new RootObjectDefinition(typeof(TestObject));
|
||||
RootObjectDefinition bd2 = new RootObjectDefinition(typeof(TestObject));
|
||||
RootObjectDefinition na1 = new RootObjectDefinition(typeof(TestObject));
|
||||
na1.IsAutowireCandidate = false;
|
||||
|
||||
lbf.RegisterObjectDefinition("bd1", bd1);
|
||||
lbf.RegisterObjectDefinition("na1", na1);
|
||||
TestObject actual = lbf.GetObject<TestObject>(); // na1 was filtered
|
||||
Assert.That(lbf.GetObject("bd1", typeof(TestObject)), Is.SameAs(actual));
|
||||
|
||||
lbf.RegisterObjectDefinition("bd2", bd2);
|
||||
Assert.That(delegate { lbf.GetObject<TestObject>(); }, Throws.Exception.TypeOf<NoSuchObjectDefinitionException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetObjectDefinitionResolvesAliases()
|
||||
{
|
||||
|
||||
@@ -354,5 +354,37 @@ namespace Spring.Objects.Factory.Xml
|
||||
Assert.AreEqual("test1", od2.DependsOn[0]);
|
||||
Assert.AreEqual(DependencyCheckingMode.Simple, od2.DependencyCheck);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsesAutowireCandidate()
|
||||
{
|
||||
DefaultListableObjectFactory of = new DefaultListableObjectFactory();
|
||||
XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of);
|
||||
reader.LoadObjectDefinitions(new StringResource(
|
||||
@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net' default-autowire-candidates='test1*,test4*'>
|
||||
<object id='test1' type='Spring.Objects.TestObject, Spring.Core.Tests' />
|
||||
<object id='test2' type='Spring.Objects.TestObject, Spring.Core.Tests' autowire-candidate='false' />
|
||||
<object id='test3' type='Spring.Objects.TestObject, Spring.Core.Tests' autowire-candidate='true' />
|
||||
<object id='test4' type='Spring.Objects.TestObject, Spring.Core.Tests' autowire-candidate='default' />
|
||||
<object id='test5' type='Spring.Objects.TestObject, Spring.Core.Tests' autowire-candidate='default' />
|
||||
</objects>
|
||||
"));
|
||||
var od = (AbstractObjectDefinition)of.GetObjectDefinition("test1");
|
||||
Assert.That(od.IsAutowireCandidate, Is.True, "No attribute set should default to true");
|
||||
|
||||
od = (AbstractObjectDefinition)of.GetObjectDefinition("test2");
|
||||
Assert.That(od.IsAutowireCandidate, Is.False, "Specifically attribute set to false should set to false");
|
||||
|
||||
od = (AbstractObjectDefinition)of.GetObjectDefinition("test3");
|
||||
Assert.That(od.IsAutowireCandidate, Is.True, "Specifically attribute set to true should set to false");
|
||||
|
||||
od = (AbstractObjectDefinition)of.GetObjectDefinition("test4");
|
||||
Assert.That(od.IsAutowireCandidate, Is.True, "Attribute set to default should check pattern and return true");
|
||||
|
||||
od = (AbstractObjectDefinition)of.GetObjectDefinition("test5");
|
||||
Assert.That(od.IsAutowireCandidate, Is.False, "Attribute set to default should check pattern and return false");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user