diff --git a/src/Spring/Spring.Core/Util/Properties.cs b/src/Spring/Spring.Core/Util/Properties.cs
index c61b9725..3d466a0f 100644
--- a/src/Spring/Spring.Core/Util/Properties.cs
+++ b/src/Spring/Spring.Core/Util/Properties.cs
@@ -30,7 +30,25 @@ namespace Spring.Util
{
///
/// An implementation of the Java Properties class.
- ///
+ ///
+ ///
+ /// For the complete syntax see java.util.Properties JavaDoc.
+ /// This class supports an extended syntax. There may also be sole keys on a line, in that case values are treated as null.
+ ///
+ ///
+ /// key1 = value
+ /// key2:
+ /// key3
+ ///
+ /// will result in the name/value pairs:
+ ///
+ /// - key1:="value"
+ /// - key2:=string.Empty
+ /// - key3:=<null>
+ ///
+ /// note, that to specify a null value, the key must not be followed by any character except newline.
+ ///
+ ///
/// Simon White
[Serializable]
public class Properties : Hashtable
@@ -122,7 +140,7 @@ namespace Spring.Util
key = keyvalue[0];
value = keyvalue[1];
- if (value.EndsWith("\\"))
+ if (value != null && value.EndsWith("\\"))
{
value = value.Substring(0, value.Length - 1);
isContinuation = true;
@@ -155,8 +173,10 @@ namespace Spring.Util
/// The string.
/// The string with all leading whitespace removed.
private static string RemoveLeadingWhitespace(string line)
- {
- string trimmed = null;
+ {
+ if (line == null) return null;
+
+ string trimmed = string.Empty;
for (int i = 0; i < line.Length; i++)
{
if (Whitespace.IndexOf(line[i]) == -1)
@@ -175,7 +195,7 @@ namespace Spring.Util
/// An array containing the key / value pair.
private static string[] SplitLine(string line)
{
- string key = null;
+ string key = line;
string value = null;
int index = 0;
@@ -202,14 +222,23 @@ namespace Spring.Util
// first ignore leading whitespace and initial separator
// (if one's there)
index++;
- if (index >= len)
+ if (index > len)
{
- return null;
- }
- value = line.Substring(index);
- value = RemoveLeadingWhitespace(value);
+ // this is an extension to support key-only lines and specifying null values
+ value = null;
+ }
+ else if (index == len)
+ {
+ value = string.Empty;
+ }
+ else
+ {
+ value = line.Substring(index);
+ value = RemoveLeadingWhitespace(value);
+ }
- if (Separators.IndexOf(value[0]) != -1)
+ if (value != null && value.Length > 0
+ && Separators.IndexOf(value[0]) != -1)
{
value = value.Substring(1);
value = RemoveLeadingWhitespace(value);
diff --git a/src/Spring/Spring.Core/Util/StringUtils.cs b/src/Spring/Spring.Core/Util/StringUtils.cs
index 29f89d73..74e741c4 100644
--- a/src/Spring/Spring.Core/Util/StringUtils.cs
+++ b/src/Spring/Spring.Core/Util/StringUtils.cs
@@ -672,6 +672,7 @@ namespace Spring.Util
/// The converted string.
public static string ConvertEscapedCharacters(string inputString)
{
+ if (inputString == null) return null;
StringBuilder sb = new StringBuilder(inputString.Length);
for (int i = 0; i < inputString.Length; i++)
{
diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs
index fe91ceb7..42b22904 100644
--- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs
+++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs
@@ -20,6 +20,7 @@
#region Imports
+using System;
using System.Collections;
using NUnit.Framework;
using Spring.Context.Support;
@@ -115,6 +116,55 @@ namespace Spring.Objects.Factory.Config
TestObject tb1 = (TestObject)ac.GetObject("tb1");
Assert.AreEqual(35, tb1.Age);
Assert.AreEqual("Erich", tb1.Name);
- }
+ }
+
+ [Test]
+ [Ignore("Does not work yet because IVariableSource cannot differentiate between invalid key and key with a null value")]
+ public void WhitespaceHandling()
+ {
+ StaticApplicationContext ac = new StaticApplicationContext();
+
+ MutablePropertyValues pvs = new MutablePropertyValues();
+ pvs.Add("name", "${name}");
+ pvs.Add("nickname", "${nickname}");
+ ac.RegisterSingleton("tb1", typeof(TestObject), pvs);
+
+ IList variableSources = new ArrayList();
+ variableSources.Add(new DictionaryVariableSource(new string[] { "name", string.Empty, "nickname", null }));
+ pvs = new MutablePropertyValues();
+ pvs.Add("VariableSources", variableSources);
+ ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs);
+ ac.Refresh();
+
+ TestObject tb1 = (TestObject)ac.GetObject("tb1");
+ Assert.AreEqual(string.Empty, tb1.Name);
+ Assert.AreEqual(null, tb1.Nickname);
+ }
+
+ [Test]
+ public void BailsOnUnresolvableVariable()
+ {
+ StaticApplicationContext ac = new StaticApplicationContext();
+
+ MutablePropertyValues pvs = new MutablePropertyValues();
+ pvs.Add("nickname", "${nickname}");
+ ac.RegisterSingleton("tb1", typeof(TestObject), pvs);
+
+ IList variableSources = new ArrayList();
+ variableSources.Add(new DictionaryVariableSource(new string[] { }));
+ pvs = new MutablePropertyValues();
+ pvs.Add("VariableSources", variableSources);
+ ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs);
+
+ try
+ {
+ ac.Refresh();
+ Assert.Fail("something changed wrt VariablePlaceholder resolution");
+ }
+ catch (ObjectDefinitionStoreException ex)
+ {
+ Assert.IsTrue( ex.Message.IndexOf("nickname") > -1 );
+ }
+ }
}
}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs b/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs
index db78ba66..5e7eab27 100644
--- a/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs
+++ b/test/Spring/Spring.Core.Tests/Util/PropertiesTests.cs
@@ -101,7 +101,7 @@ namespace Spring.Util
}
[Test]
- public void ListAndLoad ()
+ public void ListAndLoad()
{
Properties props = new Properties();
props.Add ("foo", "this");
@@ -151,6 +151,21 @@ namespace Spring.Util
Assert.IsTrue("true".Equals(props["leadingspace"]));
}
+ [Test]
+ public void WhitespaceProperties()
+ {
+ string input = "key1 =\t\nkey2:\nkey3";
+
+ Stream s = new MemoryStream(Encoding.ASCII.GetBytes(input));
+ Properties props = new Properties();
+ props.Load(s);
+
+ Assert.AreEqual(string.Empty, props["key1"], "key1 should have empty value");
+ Assert.AreEqual(string.Empty, props["key2"], "key2 should have empty value");
+ Assert.IsTrue(props.ContainsKey("key3"));
+ Assert.IsNull(props["key3"]);
+ }
+
[Test]
public void Continuation()
{