diff --git a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs
index aff582d0..7ffba218 100644
--- a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs
@@ -260,6 +260,37 @@ namespace Spring.Objects.Factory
#endif
object this[string name] { get; }
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// 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.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The type of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If there is more than a single object of the requested type defined in the factory.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ T GetObject();
+
///
/// Return an instance (possibly shared or independent) of the given object name.
///
diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs
index d0a0cd02..2ce78874 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs
@@ -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);
diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs
index ac65c8a0..2958e596 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs
@@ -1917,6 +1917,38 @@ namespace Spring.Objects.Factory.Support
return GetObjectInternal(name, null, null, false);
}
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// 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.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The type of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If there is more than a single object of the requested type defined in the factory.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ public abstract T GetObject();
+
///
/// Return an instance (possibly shared or independent) of the given object name.
///
diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs
index bad5a33d..81419945 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs
@@ -949,20 +949,41 @@ namespace Spring.Objects.Factory.Support
///
/// If the object could not be created.
///
- public T GetObject()
+ public override T GetObject()
{
IList objectNamesForType = GetObjectNamesForType(typeof(T));
+
+ if (objectNamesForType.Count > 1)
+ {
+ IList autowireCandidates = new List();
+ 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();
+ }
+ else
+ {
+ throw new NoSuchObjectDefinitionException(typeof(T), "expected single bean but found " +
+ objectNamesForType.Count + ": " + StringUtils.ArrayToCommaDelimitedString(objectNamesForType));
}
-
- return (T)GetObject(objectNamesForType[0]);
}
///
diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs
index 49e80bae..96b59a9f 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionBuilder.cs
@@ -336,6 +336,28 @@ namespace Spring.Objects.Factory.Support
return this;
}
+ ///
+ /// Sets the autowire candidate value for this definition.
+ ///
+ /// The autowire candidate value
+ ///
+ public ObjectDefinitionBuilder SetAutowireCandidate(bool autowireCandidate)
+ {
+ objectDefinition.IsAutowireCandidate = autowireCandidate;
+ return this;
+ }
+
+ ///
+ /// Sets the primary value for this definition.
+ ///
+ /// If object is primary
+ ///
+ public ObjectDefinitionBuilder SetPrimary(bool primary)
+ {
+ objectDefinition.IsPrimary = primary;
+ return this;
+ }
+
///
/// Sets the dependency check mode for this definition.
///
diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs
index eccaa27d..92243287 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Xml/DocumentDefaultsDefinition.cs
@@ -33,6 +33,7 @@ namespace Spring.Objects.Factory.Xml
private string dependencyCheck;
private string lazyInit;
private string merge;
+ private string autowireCandidates;
///
/// 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; }
}
+
+ ///
+ /// Gets or sets autowire candidates for the document that's currently parsed
+ ///
+ /// The Autowire Candidates
+ public string AutowireCandidates
+ {
+ get { return autowireCandidates; }
+ set { autowireCandidates = value; }
+ }
}
}
diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs
index 51c9835e..fe2e7643 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionConstants.cs
@@ -48,6 +48,12 @@ namespace Spring.Objects.Factory.Xml
///
public const string TrueValue = "true";
+ ///
+ /// Value of a boolean attribute that represents
+ /// .
+ ///
+ public const string FalseValue = "false";
+
///
/// Signifies that a default value is to be applied.
///
@@ -90,6 +96,11 @@ namespace Spring.Objects.Factory.Xml
///
public const string DefaultAutowireAttribute = "default-autowire";
+ ///
+ /// Specifies the default autowire candidates.
+ ///
+ public const string DefaultAutowireCandidatesAttribute = "default-autowire-candidates";
+
///
/// Specifies the default collection merge mode.
///
@@ -586,6 +597,11 @@ namespace Spring.Objects.Factory.Xml
///
public const string AutowireAttribute = "autowire";
+ ///
+ /// The autowiring mode for an individual object definition.
+ ///
+ public const string AutowireCandidateAttribute = "autowire-candidate";
+
///
/// Attribute element to farther deifne the qualifier of an object
///
diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs
index d4a64c38..7bdf0f1f 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectDefinitionParserHelper.cs
@@ -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;
}
diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs
index 2188fdf1..df704dcb 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs
@@ -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);
diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd
index c5febc79..8f084e61 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd
+++ b/src/Spring/Spring.Core/Objects/Factory/Xml/spring-objects-2.0.xsd
@@ -500,10 +500,25 @@
+ 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.
+ -->
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs
index c9b66d4f..94869bd5 100644
--- a/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs
+++ b/test/Spring/Spring.Core.Tests/Objects/Factory/DefaultListableObjectFactoryTests.cs
@@ -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(); }, Throws.Exception.TypeOf());
+ }
+
+ [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(); // na1 was filtered
+ Assert.That(lbf.GetObject("bd1", typeof(TestObject)), Is.SameAs(actual));
+
+ lbf.RegisterObjectDefinition("bd2", bd2);
+ Assert.That(delegate { lbf.GetObject(); }, Throws.Exception.TypeOf());
+ }
+
[Test]
public void GetObjectDefinitionResolvesAliases()
{
diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs
index 45aabde2..5fe77be8 100644
--- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs
+++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectDefinitionReaderTests.cs
@@ -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(
+@"
+
+
+
+
+
+
+
+"));
+ 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");
+ }
+
}
}
\ No newline at end of file