Fix ReferenceNode, so that it doesnt throw KeyNotFoundException when current context wasn't provided.
This commit is contained in:
committed by
Marko Lahma
parent
e4438e6933
commit
9a4577389c
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a reference to a Spring-managed object.
|
||||
/// </summary>
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
[Serializable]
|
||||
public class ReferenceNode : BaseNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new instance
|
||||
/// </summary>
|
||||
public ReferenceNode():base()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Represents a reference to a Spring-managed object.
|
||||
/// </summary>
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
[Serializable]
|
||||
public class ReferenceNode : BaseNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new instance
|
||||
/// </summary>
|
||||
public ReferenceNode() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance from SerializationInfo
|
||||
/// </summary>
|
||||
protected ReferenceNode(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value for the integer literal node.
|
||||
/// </summary>
|
||||
/// <param name="context">Context to evaluate expressions against.</param>
|
||||
/// <param name="evalContext">Current expression evaluation context.</param>
|
||||
/// <returns>Node's value.</returns>
|
||||
protected override object Get(object context, EvaluationContext evalContext)
|
||||
{
|
||||
IApplicationContext ctx;
|
||||
string objectName;
|
||||
/// <summary>
|
||||
/// Create a new instance from SerializationInfo
|
||||
/// </summary>
|
||||
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;
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Returns a value for the integer literal node.
|
||||
/// </summary>
|
||||
/// <param name="context">Context to evaluate expressions against.</param>
|
||||
/// <param name="evalContext">Current expression evaluation context.</param>
|
||||
/// <returns>Node's value.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <author>Erich Eichinger</author>
|
||||
[TestFixture]
|
||||
public class ReferenceNodeTests
|
||||
{
|
||||
public class MyTestObject
|
||||
{
|
||||
public object MyField;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <author>Erich Eichinger</author>
|
||||
[TestFixture]
|
||||
public class ReferenceNodeTests
|
||||
{
|
||||
private class MyTestObject
|
||||
{
|
||||
public object MyField { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesntCallContextRegistryForLocalObjectFactoryReferences()
|
||||
{
|
||||
string xml = string.Format(
|
||||
@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
[TearDown]
|
||||
public void TearDown() => ContextRegistry.Clear();
|
||||
|
||||
[Test]
|
||||
public void DoesNotCallContextRegistryForLocalObjectFactoryReferences()
|
||||
{
|
||||
var xml = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='foo' type='{0}'>
|
||||
<object id='foo' type='{typeof(MyTestObject).AssemblyQualifiedName}'>
|
||||
<property name='MyField' expression='@(theObject)' />
|
||||
</object>
|
||||
</objects>"
|
||||
, typeof(MyTestObject).AssemblyQualifiedName
|
||||
);
|
||||
</objects>";
|
||||
|
||||
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 = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
|
||||
</objects>";
|
||||
|
||||
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<string, object>());
|
||||
|
||||
Assert.That(value, Is.SameAs(expectedObject));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ThrowsApplicationContextException_WhenContextNotRegistered()
|
||||
{
|
||||
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
|
||||
</objects>";
|
||||
|
||||
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
|
||||
ContextRegistry.RegisterContext(defaultContext);
|
||||
|
||||
var expression = Expression.Parse("@(anotherContext:theObject).Value");
|
||||
void Get() => expression.GetValue(null, new Dictionary<string, object>());
|
||||
|
||||
Assert.That(Get, Throws.InstanceOf<ApplicationContextException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenContextNameSpecifiedInExpression_UseThatContext()
|
||||
{
|
||||
const string anotherContextName = "AnotherContext";
|
||||
|
||||
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
|
||||
</objects>";
|
||||
|
||||
var anotherXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
|
||||
</objects>";
|
||||
|
||||
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<string, object>());
|
||||
|
||||
Assert.That(resolvedObject, Is.SameAs(expectedObject));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UseObjectFactoryFromVariables()
|
||||
{
|
||||
const string anotherContextName = "AnotherContext";
|
||||
|
||||
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
|
||||
</objects>";
|
||||
|
||||
var anotherXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
|
||||
</objects>";
|
||||
|
||||
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
|
||||
ContextRegistry.RegisterContext(defaultContext);
|
||||
|
||||
var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName);
|
||||
var variables = new Dictionary<string, object>
|
||||
{
|
||||
[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 = $@"<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<objects xmlns='http://www.springframework.net'>
|
||||
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
|
||||
</objects>";
|
||||
|
||||
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
|
||||
ContextRegistry.RegisterContext(defaultContext);
|
||||
|
||||
var variables = new Dictionary<string, object>
|
||||
{
|
||||
[Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = new object()
|
||||
};
|
||||
|
||||
var expression = Expression.Parse("@(theObject)");
|
||||
|
||||
void Get() => expression.GetValue(null, variables);
|
||||
|
||||
Assert.That(Get, Throws.InstanceOf<InvalidCastException>());
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user