diff --git a/src/Spring/Spring.Core/Expressions/ReferenceNode.cs b/src/Spring/Spring.Core/Expressions/ReferenceNode.cs
index 27f4c4f3..971be72c 100644
--- a/src/Spring/Spring.Core/Expressions/ReferenceNode.cs
+++ b/src/Spring/Spring.Core/Expressions/ReferenceNode.cs
@@ -18,78 +18,80 @@
#endregion
-using System;
-using System.Runtime.Serialization;
using Spring.Expressions;
using Spring.Objects.Factory;
+using System;
+using System.Runtime.Serialization;
namespace Spring.Context.Support
{
- ///
- /// Represents a reference to a Spring-managed object.
- ///
- /// Aleksandar Seovic
- [Serializable]
- public class ReferenceNode : BaseNode
- {
- ///
- /// Create a new instance
- ///
- public ReferenceNode():base()
- {
- }
+ ///
+ /// Represents a reference to a Spring-managed object.
+ ///
+ /// Aleksandar Seovic
+ [Serializable]
+ public class ReferenceNode : BaseNode
+ {
+ ///
+ /// Create a new instance
+ ///
+ public ReferenceNode() { }
- ///
- /// Create a new instance from SerializationInfo
- ///
- protected ReferenceNode(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
- ///
- /// Returns a value for the integer literal node.
- ///
- /// Context to evaluate expressions against.
- /// Current expression evaluation context.
- /// Node's value.
- protected override object Get(object context, EvaluationContext evalContext)
- {
- IApplicationContext ctx;
- string objectName;
+ ///
+ /// Create a new instance from SerializationInfo
+ ///
+ protected ReferenceNode(SerializationInfo info, StreamingContext context)
+ : base(info, context) { }
- if (this.getNumberOfChildren() == 2)
- {
- string contextName = this.getFirstChild().getText();
- objectName = this.getFirstChild().getNextSibling().getText();
- ctx = ContextRegistry.GetContext(contextName);
- if (ctx == null)
- {
- throw new ArgumentException(string.Format("Context '{0}' is not registered.", contextName));
- }
- }
- else
- {
- objectName = this.getFirstChild().getText();
- IObjectFactory currentObjectFactory = (evalContext.Variables != null)
- ? (IObjectFactory)evalContext.Variables[Expression.ReservedVariableNames.CurrentObjectFactory]
- : null;
+ ///
+ ///
+ /// Returns a value for the integer literal node.
+ ///
+ /// Context to evaluate expressions against.
+ /// Current expression evaluation context.
+ /// Node's value.
+ protected override object Get(object context, EvaluationContext evalContext)
+ {
+ var objectName = ResolveNames(out var contextName);
- // this is a local reference within an object factory
- if (currentObjectFactory != null)
- {
- return currentObjectFactory.GetObject(objectName);
- }
+ var sourceContext = SelectSourceContext(evalContext, contextName);
- // else lookup in default context
- ctx = ContextRegistry.GetContext();
- if (ctx == null)
- {
- throw new ArgumentException("No context registered.");
- }
- }
+ return sourceContext.GetObject(objectName);
+ }
- return ctx.GetObject(objectName);
- }
- }
+ private string ResolveNames(out string contextName)
+ {
+ var hasContextDefined = getNumberOfChildren() == 2;
+
+ if (hasContextDefined)
+ {
+ contextName = getFirstChild().getText();
+ return getFirstChild().getNextSibling().getText();
+ }
+
+ contextName = null;
+ return getFirstChild().getText();
+ }
+
+ private static IObjectFactory SelectSourceContext(EvaluationContext evalContext, string contextName)
+ {
+ if (contextName != null)
+ return ContextRegistry.GetContext(contextName) ?? throw new ArgumentException($"Context '{contextName}' is not registered.");
+
+ if (TryGetFromCurrentContext(evalContext, out var currentObjectFactory))
+ return (IObjectFactory)currentObjectFactory;
+
+ return ContextRegistry.GetContext() ?? throw new ArgumentException("No context registered.");
+ }
+
+ private static bool TryGetFromCurrentContext(EvaluationContext evalContext, out object currentObjectFactory)
+ {
+ currentObjectFactory = null;
+
+ if (evalContext.Variables is null)
+ return false;
+
+ return evalContext.Variables.TryGetValue(Expression.ReservedVariableNames.CurrentObjectFactory, out currentObjectFactory);
+ }
+ }
}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs
index 80844794..39cfe1eb 100644
--- a/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs
+++ b/test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs
@@ -20,46 +20,178 @@
#region Imports
-using System.Text;
+using System;
+
using NUnit.Framework;
+using Spring.Context;
+using Spring.Context.Support;
using Spring.Core.IO;
using Spring.Objects.Factory.Xml;
+using System.Collections.Generic;
+using System.Text;
#endregion
namespace Spring.Expressions
{
- ///
- ///
- ///
- /// Erich Eichinger
- [TestFixture]
- public class ReferenceNodeTests
- {
- public class MyTestObject
- {
- public object MyField;
- }
+ ///
+ ///
+ ///
+ /// Erich Eichinger
+ [TestFixture]
+ public class ReferenceNodeTests
+ {
+ private class MyTestObject
+ {
+ public object MyField { get; set; }
+ }
- [Test]
- public void DoesntCallContextRegistryForLocalObjectFactoryReferences()
- {
- string xml = string.Format(
- @"
+ [TearDown]
+ public void TearDown() => ContextRegistry.Clear();
+
+ [Test]
+ public void DoesNotCallContextRegistryForLocalObjectFactoryReferences()
+ {
+ var xml = $@"
- "
- , typeof(MyTestObject).AssemblyQualifiedName
- );
+";
- XmlObjectFactory of = new XmlObjectFactory(new StringResource(xml, Encoding.UTF8));
- object theObject = new object();
- of.RegisterSingleton("theObject", theObject);
+ var objectFactory = new XmlObjectFactory(new StringResource(xml, Encoding.UTF8));
+ var theObject = new object();
+ objectFactory.RegisterSingleton("theObject", theObject);
- MyTestObject to = (MyTestObject) of.GetObject("foo");
- Assert.AreSame( theObject, to.MyField );
- }
- }
+ var to = (MyTestObject)objectFactory.GetObject("foo");
+ Assert.That(theObject, Is.SameAs(to.MyField));
+ }
+
+ [Test]
+ public void UseDefaultContextRegistryWhenNoContextProvided()
+ {
+ var defaultXml = $@"
+
+
+";
+
+ var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
+ ContextRegistry.RegisterContext(defaultContext);
+
+ var expectedObject = defaultContext.GetObject("theObject");
+
+ var expression = Expression.Parse("@(theObject)");
+ var value = expression.GetValue(null, new Dictionary());
+
+ Assert.That(value, Is.SameAs(expectedObject));
+ }
+
+ [Test]
+ public void ThrowsApplicationContextException_WhenContextNotRegistered()
+ {
+ var defaultXml = $@"
+
+
+";
+
+ var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
+ ContextRegistry.RegisterContext(defaultContext);
+
+ var expression = Expression.Parse("@(anotherContext:theObject).Value");
+ void Get() => expression.GetValue(null, new Dictionary());
+
+ Assert.That(Get, Throws.InstanceOf());
+ }
+
+ [Test]
+ public void WhenContextNameSpecifiedInExpression_UseThatContext()
+ {
+ const string anotherContextName = "AnotherContext";
+
+ var defaultXml = $@"
+
+
+";
+
+ var anotherXml = $@"
+
+
+";
+
+ var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
+ ContextRegistry.RegisterContext(defaultContext);
+
+ var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName);
+ ContextRegistry.RegisterContext(anotherContext);
+
+ var expectedObject = anotherContext.GetObject("theObject");
+
+ var expression = Expression.Parse($"@({anotherContextName}:theObject)");
+ var resolvedObject = expression.GetValue(null, new Dictionary());
+
+ Assert.That(resolvedObject, Is.SameAs(expectedObject));
+ }
+
+ [Test]
+ public void UseObjectFactoryFromVariables()
+ {
+ const string anotherContextName = "AnotherContext";
+
+ var defaultXml = $@"
+
+
+";
+
+ var anotherXml = $@"
+
+
+";
+
+ var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
+ ContextRegistry.RegisterContext(defaultContext);
+
+ var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName);
+ var variables = new Dictionary
+ {
+ [Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = anotherContext.ObjectFactory
+ };
+ var expectedObject = anotherContext.GetObject("theObject");
+
+ var expression = Expression.Parse("@(theObject)");
+ var resolvedObject = expression.GetValue(null, variables);
+
+ Assert.That(resolvedObject, Is.SameAs(expectedObject));
+ }
+
+ [Test]
+ public void ShouldThrowException_WhenFactoryProvidedInVariables_IsNotOfTypeIObjectFactory()
+ {
+ var defaultXml = $@"
+
+
+";
+
+ var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
+ ContextRegistry.RegisterContext(defaultContext);
+
+ var variables = new Dictionary
+ {
+ [Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = new object()
+ };
+
+ var expression = Expression.Parse("@(theObject)");
+
+ void Get() => expression.GetValue(null, variables);
+
+ Assert.That(Get, Throws.InstanceOf());
+ }
+
+ private static GenericApplicationContext GetContextFromXmlString(string xmlString, string contextName)
+ {
+ var stringResource = new StringResource(xmlString, Encoding.UTF8);
+ var objectFactory = new XmlObjectFactory(stringResource);
+
+ return new GenericApplicationContext(objectFactory) { Name = contextName };
+ }
+ }
}
\ No newline at end of file