diff --git a/doc/reference/src/objects.xml b/doc/reference/src/objects.xml index dae287b8..0cfaa101 100644 --- a/doc/reference/src/objects.xml +++ b/doc/reference/src/objects.xml @@ -34,11 +34,11 @@ principle The Spring.Core assembly provides the basis for - the Spring.NET Inversion of Control container. The IObjectFactory + the Spring.NET Inversion of Control container. The IObjectFactory interface provides an advanced configuration mechanism capable of managing - objects of any nature. The IApplicationContext + objects of any nature. The IApplicationContext interface builds on top of the IObjectFactory (it is a sub-interface) and adds other functionality such as easier integration with Spring.NET's Aspect Oriented Programming (AOP) features, message @@ -187,12 +187,12 @@ IObjectFactory factory = context; ASP.NET pages. You may be wondering what the assembly URL is all about. The above - example uses Spring.NET's IResource - abstraction. The IResource interface - provides a simple and uniform interface to a wide array of IO resources - that can represent themselves as System.IO.Stream. An - example for a file based resource, not using the URL syntax but an + example uses Spring.NET's IResource + abstraction. The IResource interface provides a + simple and uniform interface to a wide array of IO resources that can + represent themselves as System.IO.Stream. An example + for a file based resource, not using the URL syntax but an implementation of the IResource interface for file is shown below.[C#] IResource input = new FileSystemResource ("objects.xml"); @@ -207,11 +207,19 @@ IObjectFactory factory = new XmlObjectFactory(input); The following snippet shows the use of the URI syntax for referring to a resource that has been embedded inside a .NET assembly, - assembly://<AssemblyName>/<NameSpace>/<ResourceName> - - To create an embedded resource using Visual Studio you must set the Build Action of the .xml configuration file to Embedded Resource in the file property editor. Also, you will need to explicitly rebuild the project containing the configuration file if it is the only change you make between successive builds. If using NAnt to build, add a <resources> section to the csc task. For example usage, look at the Spring.Core.Tests.build file included the distribution. - The IResource abstraction is explained - further in . + assembly://<AssemblyName>/<NameSpace>/<ResourceName>. + The IResource abstraction is explained further in + . + + + To create an embedded resource using Visual Studio you must set + the Build Action of the .xml configuration file to Embedded Resource + in the file property editor. Also, you will need to explicitly rebuild + the project containing the configuration file if it is the only change + you make between successive builds. If using NAnt to build, add a + <resources> section to the csc task. For example usage, look at + the Spring.Core.Tests.build file included the distribution. + The preferred way to create an IApplicationContext or @@ -1254,6 +1262,10 @@ namespace SimpleApp choice will already have been made for you - a legacy class may not expose any setter methods, and so constructor injection will be the only type of DI available to you. + + Since you can mix both, Constructor- and Setter-based DI, it + is a good rule of thumb to use constructor arguments for mandatory + dependencies and setters for optional dependencies. The IObjectFactory supports both of these @@ -1278,8 +1290,6 @@ namespace SimpleApp IObjectFactory or IApplicationContext variant that supports XML format configuration files. - - @@ -1288,27 +1298,21 @@ namespace SimpleApp static-factory method when that is used instead of a normal constructor. These dependencies will be provided to the object, when the object is actually created. - - Each property or constructor argument is either an actual definition of the value to set, or a reference to another object in the container. - - - Each - property or constructor argument which is a value must be able - to be converted from whatever format it was specified in, to the - actual System.Type of that property or - constructor argument. By default Spring.NET can convert a value - supplied in string format to all built-in types, such as - int, long, + Each property or constructor argument which is a value + must be able to be converted from whatever format it was + specified in, to the actual System.Type of + that property or constructor argument. By default Spring.NET can + convert a value supplied in string format to all built-in types, + such as int, long, string, bool, etc. Spring.NET uses TypeConverter definitions to be able to convert string values to other, arbitrary types. @@ -1556,7 +1560,7 @@ public class MixedIocObject <constructor-arg/> elements for this purpose.a - + Straight values (primitives, <literal>strings</literal>, etc.) @@ -1579,16 +1583,14 @@ public class MixedIocObject for configuration of its ConnectionString property. - - <objects xmlns="http://www.springframework.net"> + <objects xmlns="http://www.springframework.net"> <object id="myConnection" type="System.Data.SqlClient.SqlConnection"> <!-- results in a call to the setter of the ConnectionString property --> <property name="ConnectionString" value="Integrated Security=SSPI;database=northwind;server=mySQLServer"/> </object> -</objects> - +</objects> The idref element @@ -1629,6 +1631,24 @@ public class MixedIocObject <idref local="theTargetObject"/> </property> + + + Whitespace Handling + + Usually all leading and trailing whitespaces are trimmed from + a <value /> element's text. In some cases it is necessary to + maintain whitespaces exactly as they are written into the xml + element. The parser does understand the xml:space attribute in this + case: + + <property name="myProp"> + <value xml:space="preserve"> &#x000a;&#x000d;&#x0009;</value> +</property> + + The above configuration will result in the string " \n\r\t". + Note, that you don't have to explicitely specifiy the 'xml' + namespace on top of your configuration. + @@ -1689,9 +1709,7 @@ public class MixedIocObject may have the same name as the parent), and needs the original object so it may wrap it. - - <ref parent="someObject"/> - + <ref parent="someObject"/> @@ -1773,13 +1791,10 @@ public class MixedIocObject additive behavior for collection properties that are exposed in this manner. - - Note that the value of a Dictionary entry, or a set value, - can also again be any of the elements: - - (object | ref | idref | expression | list | set | dictionary | - name-values | value | null) - + Note that the value of a Dictionary entry, or a set + value, can also again be any of the elements: + (object | ref | idref | expression | list | set | dictionary | + name-values | value | null) The shortcut forms for value and references are useful to reduce XML verbosity when setting collection properties. See - The use of the property expression parser in Release 1.0.2 - changed how you configure indexer properties. The following section - describes this usage. The older style configuration uses the - following syntax <object id="objectWithIndexer" type="Spring.Objects.TestObject, Spring.Core.Tests"> + + The use of the property expression parser in Release 1.0.2 + changed how you configure indexer properties. The following section + describes this usage. + + The older style configuration uses the following syntax + <object id="objectWithIndexer" type="Spring.Objects.TestObject, Spring.Core.Tests"> <property name="Item[0]" value="my string value"/> </object> You can also change the name used to identify - the indexer by adorning your indexer method declaration with the - attribute [IndexerName("MyItemName")]. You would - then use the string MyItemName[0] to configure the - first element of that indexer. There are some - limitations to be aware in the older indexer configuration. The - indexer can only be of a single parameter that is convertible from a - string to the indexer parameter type. Also, multiple indexers are not - supported. You can get around that last limitation currently if you - use the IndexerName attribute. + the indexer by adorning your indexer method declaration with the + attribute [IndexerName("MyItemName")]. You would + then use the string MyItemName[0] to configure + the first element of that indexer. + + There are some limitations to be aware in the older indexer + configuration. The indexer can only be of a single parameter that is + convertible from a string to the indexer parameter type. Also, + multiple indexers are not supported. You can get around that last + limitation currently if you use the IndexerName attribute. + @@ -2035,11 +2055,13 @@ public class MixedIocObject <constructor-arg index="0" ref="anotherObject"/> - The shortcut form is equivalent to a <ref - object="xxx"> element; there is no shortcut for either - the <ref local="xxx"> or <ref - parent="xxx"> elements. For a local or parent - ref, you must still use the long form. + + The shortcut form is equivalent to a <ref + object="xxx"> element; there is no shortcut for either + the <ref local="xxx"> or <ref + parent="xxx"> elements. For a local or parent + ref, you must still use the long form. + Finally, the entry element allows a shortcut form the specify the key and/or value of a dictionary, in the form of key/key-ref and @@ -2059,33 +2081,34 @@ public class MixedIocObject Compound property names and Spring expression references - - Note that compound or nested property names are perfectly legal - when setting object properties. Property names are interpreted using the - Spring Expression Language (SpEL) and - therefore can leverage its many features to set property names. For - example, in this object definition a simple nested property name is - configured + Note that compound or nested property names are perfectly legal + when setting object properties. Property names are interpreted using + the Spring Expression Language + (SpEL) and therefore can leverage its many features to set property + names. For example, in this object definition a simple nested property + name is configured - <object id="foo" type="Spring.Foo, Spring.Foo"> + <object id="foo" type="Spring.Foo, Spring.Foo"> <property name="bar.baz.name" value="Bingo"/> </object> - As an example of some alternative ways to declare the property - name, you can use SpEL's support for indexers to configure a Dictionary - key value pair as an alternative to the nested - <dictionary> element. More importantly, you can - use the 'expression' element to refer to a Spring expression as the - value of the property. Simple examples of this are shown below + As an example of some alternative ways to declare the property + name, you can use SpEL's support for indexers to configure a + Dictionary key value pair as an alternative to the nested + <dictionary> element. More importantly, you + can use the 'expression' element to refer to a Spring expression as + the value of the property. Simple examples of this are shown + below - <property name=“minValue” expression=“int.MinValue” /> + <property name=“minValue” expression=“int.MinValue” /> <property name=“weekFromToday” expression="DateTime.Today + 7"/> - Using SpEL's support for method evaluation, you can easily call - static method on various helper classes in your XML - configuraiton. + Using SpEL's support for method evaluation, you can easily call + static method on various helper classes in your XML + configuraiton. + @@ -2120,15 +2143,15 @@ public class MixedIocObject <object id="manager" type="Examples.ManagerObject, ExamplesLibrary" /> <object id="accountDao" type="Examples.AdoAccountDao, ExamplesLibrary" /> - - The 'depends-on' attribute and property is - used not only to specify an initialization time dependency, but also - to specify the corresponding destroy time dependency (in the case of - singleton objects only). Dependent objects that are defined in the - 'depends-on' attribute will be destroyed after the relevant object - itself is destroyed. This thus allows you to control shutdown order - too - + + The 'depends-on' attribute and property is + used not only to specify an initialization time dependency, but also + to specify the corresponding destroy time dependency (in the case of + singleton objects only). Dependent objects that are defined in the + 'depends-on' attribute will be destroyed after the relevant object + itself is destroyed. This thus allows you to control shutdown order + too + @@ -2439,7 +2462,7 @@ public class MixedIocObject instance of object B every time one is needed. One solution to this problem is to forego some inversion of - control. Object A can be made aware of the container by implementing the IObjectFactoryAware interface, and System.Reflection.Emit namespace. You can read more - about the motivation for Method Injection in this blog - entry. + about the motivation for Method Injection in this blog + entry. So if you look at the code from the previous code snipped (the CommandManager class), the Spring container is @@ -2944,7 +2967,7 @@ public class MyClassFactory return ... // implementation elided for clarity... } } <object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" /> - + <object id="paramsMethodObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core"> <property name="TargetObject" ref="myMethodObject"/> <property name="TargetMethod" value="CreateObject"/> @@ -2976,11 +2999,12 @@ public class MyClassFactory The LogFactoryObject is useful when you would like to share a Common.Logging log object across a number of classes instead of creating a logging instance per class or class hierarchy. - Information on the Common.Logging project can be found here. In the example - shown below the same logging instance, with a logging category name of - "DAOLogger", is used in both the SimpleAccountDao and SimpleProductDao - data access objects. <objects xmlns="http://www.springframework.net" + Information on the Common.Logging project can be found here. In the + example shown below the same logging instance, with a logging category + name of "DAOLogger", is used in both the SimpleAccountDao and + SimpleProductDao data access objects. <objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd" > @@ -3545,15 +3569,11 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo - Generally, the use of the - - IInitializingObject - - can be avoided. The - - Spring.Core - - library provides support for a generic init-method, given to the object definition in the object configuration store (be it XML, or a database, etc). + Generally, the use of the + IInitializingObject can be avoided. The + Spring.Core library provides support for a + generic init-method, given to the object definition in the object + configuration store (be it XML, or a database, etc). <object id="exampleInitObject" type="Examples.ExampleObject" init-method="init"/> @@ -3575,23 +3595,15 @@ public class AnotherExampleObject : IInitializingObject } but does not couple the code to Spring.NET. - When deploying an object in - - prototype - - mode, the lifecycle of the object changes slightly. By definition, Spring.NET cannot manage the complete lifecycle of a non-singleton / - - prototype - - object, since after it is created, it is given to the client and the container no longer keeps a reference to the object. You can think of Spring.NET's role when talking about a non-singleton ( - - prototype - - ) object as a replacement for the - - new - - operator. Any lifecycle aspects past that point have to be handled by the client. + When deploying an object in prototype mode, + the lifecycle of the object changes slightly. By definition, + Spring.NET cannot manage the complete lifecycle of a non-singleton / + prototype object, since after it is created, it + is given to the client and the container no longer keeps a reference + to the object. You can think of Spring.NET's role when talking about + a non-singleton ( prototype ) object as a + replacement for the new operator. Any lifecycle + aspects past that point have to be handled by the client. @@ -3615,11 +3627,12 @@ public class AnotherExampleObject : IInitializingObject - Note: If you choose you can avoid having your class + Note: If you choose you can avoid having your class implement IDisposable since the Spring.Core library provides support for a generic destroy-method, given to the object definition in the object - configuration store (be it XML, or a database, etc). + configuration store (be it XML, or a database, + etc). <object id="exampleInitObject" type="Examples.ExampleObject" destroy-method="cleanup"/> @@ -3762,15 +3775,14 @@ public class AnotherExampleObject : IDisposable ignore object definitions that are considered abstract. - Application contexts (but not simple object factories) will by default pre-instantiate all singletons. Therefore it is important (at least for singleton objects) that if you have a (parent) object definition which you intend to use only as a template, and this definition specifies a class, you must make sure to set the - - abstract - - attribute to - - true - - , otherwise the application context will actually (attempt to) pre-instantiate the abstract object. + Application contexts (but not simple object factories) will by + default pre-instantiate all singletons. Therefore it is important (at + least for singleton objects) that if you have a (parent) object + definition which you intend to use only as a template, and this + definition specifies a class, you must make sure to set the + abstract attribute to true , + otherwise the application context will actually (attempt to) + pre-instantiate the abstract object. @@ -4343,7 +4355,7 @@ cfg.setLocation(new FileSystemResource("ado.properties")); cfg.PostProcessObjectFactory(factory); This + xml:id="objects-factory-autodetect-objectfactorypostprocessors" />This explicit registration step is not convenient, and this is one of the reasons why the various IApplicationContext implementations are preferred above plain @@ -4489,19 +4501,14 @@ cfg.PostProcessObjectFactory(factory); expect using NameValueCollection.Add. - In an ASP.NET environment you must specify the full, four-part name of the assembly when using a - - NameValueFileSectionHandler - - - - + In an ASP.NET environment you must specify the full, four-part + name of the assembly when using a + NameValueFileSectionHandler <section name="hibernateConfiguration" type="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> - - - + @@ -4751,8 +4758,8 @@ cfg.PostProcessObjectFactory(factory); FieldRetrievingFactoryObject. An additional use of creating an custom IFactoryObject implementation is to retrieve an object from an embedded resource file and use it to set another objects - dependency. An example of this is provided here. + dependency. An example of this is provided here. Finally, there is sometimes a need to ask a container for an actual IFactoryObject instance itself, not the object @@ -4846,11 +4853,11 @@ cfg.PostProcessObjectFactory(factory); IObjectFactory or IApplicationContext? - Short version: use an - IApplicationContext - unless you have a really good reason for not doing so. For - those of you that are looking for slightly more depth as to the 'but - why' of the above recommendation, keep reading. + Short version: use an + IApplicationContext unless you + have a really good reason for not doing so. For those of you that are + looking for slightly more depth as to the 'but why' of the above + recommendation, keep reading. As the IApplicationContext includes all the functionality the object factory via its inheritance of the @@ -4878,8 +4885,9 @@ cfg.PostProcessObjectFactory(factory); IObjectFactory capabilities in a lot more depth than the said feature matrix.) - + + +
Feature Matrix @@ -4889,88 +4897,57 @@ cfg.PostProcessObjectFactory(factory); Feature - - IObjectFactory - + IObjectFactory - - IApplicationContext - + IApplicationContext - - Object instantiation/wiring - + Object instantiation/wiring - - Yes - + Yes - - Yes - + Yes - - Automatic IObjectPostProcessor - registration - + Automatic IObjectPostProcessor + registration - - No - + No - - Yes - + Yes - - Automatic IObjectFactoryPostProcessor - registration - + Automatic + IObjectFactoryPostProcessor + registration - - No - + No - - Yes - + Yes - - Convenient IMessageSource - access - + Convenient IMessageSource + access - - No - + No - - Yes - + Yes - - ApplicationEvent publication - + ApplicationEvent + publication - - No - + No - - Yes - + Yes @@ -5379,10 +5356,10 @@ IApplicationContext context = string GetMessage(IMessageSourceResolvable - resolvable, CultureInfo culture) : - all properties used in the methods above are also wrapped in a - class - the MessageSourceResolvable, which you - can use in this method. + resolvable, CultureInfo culture) : all properties used + in the methods above are also wrapped in a class - the + MessageSourceResolvable, which you can use in + this method. @@ -5422,11 +5399,13 @@ IApplicationContext context = defined above. - - Fallback behavior - The fallback rules for localized resources seem to have a bug that is fixed by applying Service Pack 1 for .NET 1.1. This affects the use of IMessageSource.GetMessage methods that specify CultureInfo. The core of the issue in the .NET BCL is the method ResourceManager.GetObject that accepts CultureInfo. . + The fallback rules for localized resources seem to have a bug + that is fixed by applying Service Pack 1 for .NET 1.1. This affects + the use of IMessageSource.GetMessage methods that specify CultureInfo. + The core of the issue in the .NET BCL is the method + ResourceManager.GetObject that accepts CultureInfo. Spring.NET provides two IMessageSource diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs index 4243d72c..43e907ed 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserAttribute.cs @@ -31,9 +31,6 @@ namespace Spring.Objects.Factory.Xml /// Attribute that should be used to specify the default namespace /// and schema location for a custom namespace parser. /// - /// - /// If - /// /// Aleksandar Seovic [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] public class NamespaceParserAttribute : Attribute @@ -72,14 +69,7 @@ namespace Spring.Objects.Factory.Xml /// public string SchemaLocation { - get - { - if (schemaLocationAssemblyHint != null) - { - return "assembly://" + schemaLocationAssemblyHint.Assembly.FullName + schemaLocation; - } - return schemaLocation; - } + get { return schemaLocation; } set { schemaLocation = value; } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs index d34fe0b1..cc8d7d0a 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/NamespaceParserRegistry.cs @@ -85,6 +85,19 @@ namespace Spring.Objects.Factory.Xml } } + /// + /// Constructs a "assembly://..." qualified schemaLocation url using the given type + /// to obtain the assembly name. + /// + public static string GetAssemblySchemaLocation( Type schemaLocationAssemblyHint, string schemaLocation) + { + if (schemaLocationAssemblyHint != null) + { + return "assembly://" + schemaLocationAssemblyHint.Assembly.FullName + schemaLocation; + } + return schemaLocation; + } + /// /// Returns a parser for the given namespace. /// @@ -236,6 +249,10 @@ namespace Spring.Objects.Factory.Xml if (StringUtils.IsNullOrEmpty(schemaLocation)) { schemaLocation = defaults.SchemaLocation; + if (defaults.SchemaLocationAssemblyHint != null) + { + schemaLocation = GetAssemblySchemaLocation(defaults.SchemaLocationAssemblyHint, schemaLocation); + } } } @@ -249,17 +266,26 @@ namespace Spring.Objects.Factory.Xml parsers[namespaceUri] = parser; if (StringUtils.HasText(schemaLocation) && !schemas.Contains(namespaceUri)) { - IResourceLoader resourceLoader = new ConfigurableResourceLoader(); - IResource schema = resourceLoader.GetResource(schemaLocation); - try { - schemas.Add(namespaceUri, new XmlTextReader(schema.InputStream)); - } catch (Exception e) - { - throw new ArgumentException("Could not load schema from resource = " + schema, e); - } - + RegisterSchema(namespaceUri, schemaLocation); } } + } + + /// + /// Register a schema as well-known + /// + /// + /// + private static void RegisterSchema(string namespaceUri, string schemaLocation) + { + IResourceLoader resourceLoader = new ConfigurableResourceLoader(); + IResource schema = resourceLoader.GetResource(schemaLocation); + try { + schemas.Add(namespaceUri, new XmlTextReader(schema.InputStream)); + } catch (Exception e) + { + throw new ArgumentException("Could not load schema from resource = " + schema, e); + } } /// diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs index e26bb560..33fb19eb 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs @@ -27,7 +27,7 @@ using System.Globalization; using System.IO; using System.Text; using System.Xml; - +using System.Xml.Schema; using Common.Logging; using Spring.Collections; @@ -1320,11 +1320,13 @@ namespace Spring.Objects.Factory.Xml /// protected string ParseTextValueElement(XmlElement element, string name) { - if (element == null || StringUtils.IsNullOrEmpty(element.InnerText)) - { - return String.Empty; - } - return element.InnerText; + if (element == null) return string.Empty; + + string innerText = element.InnerText; + // check the xml:space attribute + bool preserveWhitespace = 0 == string.Compare("preserve", element.GetAttribute("space", "http://www.w3.org/XML/1998/namespace"), true); + bool isEmpty = preserveWhitespace ? innerText.Length == 0 : StringUtils.IsNullOrEmpty(innerText); + return isEmpty ? String.Empty : innerText; } /// diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs index 6c6396c0..f010e8e3 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlObjectDefinitionReader.cs @@ -259,6 +259,11 @@ namespace Spring.Objects.Factory.Xml if (args.Severity == XmlSeverityType.Error) { #if !NET_1_0 + // ignore validation errors for well-known 'xml' namespace. This seems to be a bug in net 1.0 + 1.1 + if (args.Exception.Message.IndexOf("http://www.w3.org/XML/1998/namespace:") > -1) + { + return; + } throw new XmlException(args.Message, args.Exception, args.Exception.LineNumber, args.Exception.LinePosition); #else throw new XmlException(args.Message, args.Exception); diff --git a/src/Spring/Spring.Core/Spring.Core.2003.csproj b/src/Spring/Spring.Core/Spring.Core.2003.csproj index 8dfbe7b7..900ad6ba 100644 --- a/src/Spring/Spring.Core/Spring.Core.2003.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2003.csproj @@ -2059,10 +2059,6 @@ DependentUpon = "spring-objects-1.1.xsd" BuildAction = "None" /> - - + ")); @@ -105,6 +105,22 @@ namespace Spring.Objects.Factory.Xml Assert.AreEqual(string.Empty, ((TestObject) of.GetObject("test4")).Name); } + [Test] + public void WhitespaceValuesArePreservedForValueElementWhenSpaceIsSetToPreserve() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of); + reader.LoadObjectDefinitions(new StringResource( + @" + + + + + +")); + Assert.AreEqual(" \n\r\t", ((TestObject) of.GetObject("test4")).Name); + } + [Test] [ExpectedException(typeof(XmlObjectDefinitionStoreException))] public void ThrowsObjectDefinitionStoreExceptionOnValidationError()