Skip to content

Commit 9a45773

Browse files
kamilpitulalahma
authored andcommitted
Fix ReferenceNode, so that it doesnt throw KeyNotFoundException when current context wasn't provided.
1 parent e4438e6 commit 9a45773

File tree

2 files changed

+234
-100
lines changed

2 files changed

+234
-100
lines changed

src/Spring/Spring.Core/Expressions/ReferenceNode.cs

Lines changed: 71 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -18,78 +18,80 @@
1818

1919
#endregion
2020

21-
using System;
22-
using System.Runtime.Serialization;
2321
using Spring.Expressions;
2422
using Spring.Objects.Factory;
23+
using System;
24+
using System.Runtime.Serialization;
2525

2626
namespace Spring.Context.Support
2727
{
28-
/// <summary>
29-
/// Represents a reference to a Spring-managed object.
30-
/// </summary>
31-
/// <author>Aleksandar Seovic</author>
32-
[Serializable]
33-
public class ReferenceNode : BaseNode
34-
{
35-
/// <summary>
36-
/// Create a new instance
37-
/// </summary>
38-
public ReferenceNode():base()
39-
{
40-
}
41-
42-
/// <summary>
43-
/// Create a new instance from SerializationInfo
44-
/// </summary>
45-
protected ReferenceNode(SerializationInfo info, StreamingContext context)
46-
: base(info, context)
47-
{
48-
}
49-
50-
/// <summary>
51-
/// Returns a value for the integer literal node.
52-
/// </summary>
53-
/// <param name="context">Context to evaluate expressions against.</param>
54-
/// <param name="evalContext">Current expression evaluation context.</param>
55-
/// <returns>Node's value.</returns>
56-
protected override object Get(object context, EvaluationContext evalContext)
57-
{
58-
IApplicationContext ctx;
59-
string objectName;
60-
61-
if (this.getNumberOfChildren() == 2)
62-
{
63-
string contextName = this.getFirstChild().getText();
64-
objectName = this.getFirstChild().getNextSibling().getText();
65-
ctx = ContextRegistry.GetContext(contextName);
66-
if (ctx == null)
67-
{
68-
throw new ArgumentException(string.Format("Context '{0}' is not registered.", contextName));
69-
}
70-
}
71-
else
72-
{
73-
objectName = this.getFirstChild().getText();
74-
IObjectFactory currentObjectFactory = (evalContext.Variables != null)
75-
? (IObjectFactory)evalContext.Variables[Expression.ReservedVariableNames.CurrentObjectFactory]
76-
: null;
77-
78-
// this is a local reference within an object factory
79-
if (currentObjectFactory != null)
80-
{
81-
return currentObjectFactory.GetObject(objectName);
82-
}
83-
84-
// else lookup in default context
85-
ctx = ContextRegistry.GetContext();
86-
if (ctx == null)
87-
{
88-
throw new ArgumentException("No context registered.");
89-
}
90-
}
91-
92-
return ctx.GetObject(objectName);
93-
}
94-
}
28+
/// <summary>
29+
/// Represents a reference to a Spring-managed object.
30+
/// </summary>
31+
/// <author>Aleksandar Seovic</author>
32+
[Serializable]
33+
public class ReferenceNode : BaseNode
34+
{
35+
/// <summary>
36+
/// Create a new instance
37+
/// </summary>
38+
public ReferenceNode() { }
39+
40+
/// <summary>
41+
/// Create a new instance from SerializationInfo
42+
/// </summary>
43+
protected ReferenceNode(SerializationInfo info, StreamingContext context)
44+
: base(info, context) { }
45+
46+
/// <inheritdoc />
47+
/// <summary>
48+
/// Returns a value for the integer literal node.
49+
/// </summary>
50+
/// <param name="context">Context to evaluate expressions against.</param>
51+
/// <param name="evalContext">Current expression evaluation context.</param>
52+
/// <returns>Node's value.</returns>
53+
protected override object Get(object context, EvaluationContext evalContext)
54+
{
55+
var objectName = ResolveNames(out var contextName);
56+
57+
var sourceContext = SelectSourceContext(evalContext, contextName);
58+
59+
return sourceContext.GetObject(objectName);
60+
}
61+
62+
private string ResolveNames(out string contextName)
63+
{
64+
var hasContextDefined = getNumberOfChildren() == 2;
65+
66+
if (hasContextDefined)
67+
{
68+
contextName = getFirstChild().getText();
69+
return getFirstChild().getNextSibling().getText();
70+
}
71+
72+
contextName = null;
73+
return getFirstChild().getText();
74+
}
75+
76+
private static IObjectFactory SelectSourceContext(EvaluationContext evalContext, string contextName)
77+
{
78+
if (contextName != null)
79+
return ContextRegistry.GetContext(contextName) ?? throw new ArgumentException($"Context '{contextName}' is not registered.");
80+
81+
if (TryGetFromCurrentContext(evalContext, out var currentObjectFactory))
82+
return (IObjectFactory)currentObjectFactory;
83+
84+
return ContextRegistry.GetContext() ?? throw new ArgumentException("No context registered.");
85+
}
86+
87+
private static bool TryGetFromCurrentContext(EvaluationContext evalContext, out object currentObjectFactory)
88+
{
89+
currentObjectFactory = null;
90+
91+
if (evalContext.Variables is null)
92+
return false;
93+
94+
return evalContext.Variables.TryGetValue(Expression.ReservedVariableNames.CurrentObjectFactory, out currentObjectFactory);
95+
}
96+
}
9597
}

test/Spring/Spring.Core.Tests/Expressions/ReferenceNodeTests.cs

Lines changed: 163 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,46 +20,178 @@
2020

2121
#region Imports
2222

23-
using System.Text;
23+
using System;
24+
2425
using NUnit.Framework;
26+
using Spring.Context;
27+
using Spring.Context.Support;
2528
using Spring.Core.IO;
2629
using Spring.Objects.Factory.Xml;
30+
using System.Collections.Generic;
31+
using System.Text;
2732

2833
#endregion
2934

3035
namespace Spring.Expressions
3136
{
32-
/// <summary>
33-
///
34-
/// </summary>
35-
/// <author>Erich Eichinger</author>
36-
[TestFixture]
37-
public class ReferenceNodeTests
38-
{
39-
public class MyTestObject
40-
{
41-
public object MyField;
42-
}
43-
44-
[Test]
45-
public void DoesntCallContextRegistryForLocalObjectFactoryReferences()
46-
{
47-
string xml = string.Format(
48-
@"<?xml version='1.0' encoding='UTF-8' ?>
37+
/// <summary>
38+
///
39+
/// </summary>
40+
/// <author>Erich Eichinger</author>
41+
[TestFixture]
42+
public class ReferenceNodeTests
43+
{
44+
private class MyTestObject
45+
{
46+
public object MyField { get; set; }
47+
}
48+
49+
[TearDown]
50+
public void TearDown() => ContextRegistry.Clear();
51+
52+
[Test]
53+
public void DoesNotCallContextRegistryForLocalObjectFactoryReferences()
54+
{
55+
var xml = $@"<?xml version='1.0' encoding='UTF-8' ?>
4956
<objects xmlns='http://www.springframework.net'>
50-
<object id='foo' type='{0}'>
57+
<object id='foo' type='{typeof(MyTestObject).AssemblyQualifiedName}'>
5158
<property name='MyField' expression='@(theObject)' />
5259
</object>
53-
</objects>"
54-
, typeof(MyTestObject).AssemblyQualifiedName
55-
);
56-
57-
XmlObjectFactory of = new XmlObjectFactory(new StringResource(xml, Encoding.UTF8));
58-
object theObject = new object();
59-
of.RegisterSingleton("theObject", theObject);
60-
61-
MyTestObject to = (MyTestObject) of.GetObject("foo");
62-
Assert.AreSame( theObject, to.MyField );
63-
}
64-
}
60+
</objects>";
61+
62+
var objectFactory = new XmlObjectFactory(new StringResource(xml, Encoding.UTF8));
63+
var theObject = new object();
64+
objectFactory.RegisterSingleton("theObject", theObject);
65+
66+
var to = (MyTestObject)objectFactory.GetObject("foo");
67+
Assert.That(theObject, Is.SameAs(to.MyField));
68+
}
69+
70+
[Test]
71+
public void UseDefaultContextRegistryWhenNoContextProvided()
72+
{
73+
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
74+
<objects xmlns='http://www.springframework.net'>
75+
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
76+
</objects>";
77+
78+
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
79+
ContextRegistry.RegisterContext(defaultContext);
80+
81+
var expectedObject = defaultContext.GetObject("theObject");
82+
83+
var expression = Expression.Parse("@(theObject)");
84+
var value = expression.GetValue(null, new Dictionary<string, object>());
85+
86+
Assert.That(value, Is.SameAs(expectedObject));
87+
}
88+
89+
[Test]
90+
public void ThrowsApplicationContextException_WhenContextNotRegistered()
91+
{
92+
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
93+
<objects xmlns='http://www.springframework.net'>
94+
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
95+
</objects>";
96+
97+
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
98+
ContextRegistry.RegisterContext(defaultContext);
99+
100+
var expression = Expression.Parse("@(anotherContext:theObject).Value");
101+
void Get() => expression.GetValue(null, new Dictionary<string, object>());
102+
103+
Assert.That(Get, Throws.InstanceOf<ApplicationContextException>());
104+
}
105+
106+
[Test]
107+
public void WhenContextNameSpecifiedInExpression_UseThatContext()
108+
{
109+
const string anotherContextName = "AnotherContext";
110+
111+
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
112+
<objects xmlns='http://www.springframework.net'>
113+
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
114+
</objects>";
115+
116+
var anotherXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
117+
<objects xmlns='http://www.springframework.net'>
118+
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
119+
</objects>";
120+
121+
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
122+
ContextRegistry.RegisterContext(defaultContext);
123+
124+
var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName);
125+
ContextRegistry.RegisterContext(anotherContext);
126+
127+
var expectedObject = anotherContext.GetObject("theObject");
128+
129+
var expression = Expression.Parse($"@({anotherContextName}:theObject)");
130+
var resolvedObject = expression.GetValue(null, new Dictionary<string, object>());
131+
132+
Assert.That(resolvedObject, Is.SameAs(expectedObject));
133+
}
134+
135+
[Test]
136+
public void UseObjectFactoryFromVariables()
137+
{
138+
const string anotherContextName = "AnotherContext";
139+
140+
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
141+
<objects xmlns='http://www.springframework.net'>
142+
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
143+
</objects>";
144+
145+
var anotherXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
146+
<objects xmlns='http://www.springframework.net'>
147+
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
148+
</objects>";
149+
150+
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
151+
ContextRegistry.RegisterContext(defaultContext);
152+
153+
var anotherContext = GetContextFromXmlString(anotherXml, anotherContextName);
154+
var variables = new Dictionary<string, object>
155+
{
156+
[Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = anotherContext.ObjectFactory
157+
};
158+
var expectedObject = anotherContext.GetObject("theObject");
159+
160+
var expression = Expression.Parse("@(theObject)");
161+
var resolvedObject = expression.GetValue(null, variables);
162+
163+
Assert.That(resolvedObject, Is.SameAs(expectedObject));
164+
}
165+
166+
[Test]
167+
public void ShouldThrowException_WhenFactoryProvidedInVariables_IsNotOfTypeIObjectFactory()
168+
{
169+
var defaultXml = $@"<?xml version='1.0' encoding='UTF-8' ?>
170+
<objects xmlns='http://www.springframework.net'>
171+
<object id='theObject' type='{typeof(MyTestObject).AssemblyQualifiedName}'/>
172+
</objects>";
173+
174+
var defaultContext = GetContextFromXmlString(defaultXml, AbstractApplicationContext.DefaultRootContextName);
175+
ContextRegistry.RegisterContext(defaultContext);
176+
177+
var variables = new Dictionary<string, object>
178+
{
179+
[Expression.ReservedVariableNames.RESERVEDPREFIX + "CurrentObjectFactory"] = new object()
180+
};
181+
182+
var expression = Expression.Parse("@(theObject)");
183+
184+
void Get() => expression.GetValue(null, variables);
185+
186+
Assert.That(Get, Throws.InstanceOf<InvalidCastException>());
187+
}
188+
189+
private static GenericApplicationContext GetContextFromXmlString(string xmlString, string contextName)
190+
{
191+
var stringResource = new StringResource(xmlString, Encoding.UTF8);
192+
var objectFactory = new XmlObjectFactory(stringResource);
193+
194+
return new GenericApplicationContext(objectFactory) { Name = contextName };
195+
}
196+
}
65197
}

0 commit comments

Comments
 (0)