improved exception handling w.r.t. loading object definitions

This commit is contained in:
eeichinger
2008-10-23 17:31:16 +00:00
parent b419c29186
commit 9b45c907e3
16 changed files with 304 additions and 50 deletions

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <EFBFBD> 2002-2005 the original author or authors.
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ using Common.Logging;
using Spring.Core;
using Spring.Core.TypeResolution;
using Spring.Objects;
using Spring.Reflection.Dynamic;
using Spring.Util;
#endregion
@@ -546,8 +547,7 @@ namespace Spring.Context.Support
protected override IApplicationContext InvokeContextConstructor(
ConstructorInfo ctor)
{
return (IApplicationContext) ObjectUtils.InstantiateType(
ctor, new object[] {ContextName, CaseSensitive, Resources});
return (IApplicationContext)(new SafeConstructor(ctor).Invoke(new object[] {ContextName, CaseSensitive, Resources}));
}
}
@@ -574,8 +574,7 @@ namespace Spring.Context.Support
protected override IApplicationContext InvokeContextConstructor(
ConstructorInfo ctor)
{
return (IApplicationContext) ObjectUtils.InstantiateType(
ctor, new object[] {ContextName, CaseSensitive, this.parentContext, Resources});
return (IApplicationContext)(new SafeConstructor(ctor).Invoke(new object[] {ContextName, CaseSensitive, this.parentContext, Resources}));
}
private IApplicationContext parentContext;
@@ -638,4 +637,4 @@ namespace Spring.Context.Support
#endregion
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <EFBFBD> 2002-2005 the original author or authors.
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -139,9 +139,8 @@ namespace Spring.Objects.Factory
IResource resourceLocation,
string name,
string message,
Exception rootCause) : this
(resourceLocation == null ? string.Empty : resourceLocation.Description,
name, message, rootCause)
Exception rootCause)
: this( (resourceLocation == null ? string.Empty : resourceLocation.Description), name, message, rootCause)
{
}
@@ -165,10 +164,10 @@ namespace Spring.Objects.Factory
string name,
string message,
Exception rootCause)
: base(
: base(
string.Format(
"Error registering object with name '{0}' defined in '{1}' : {2}",
name,
"Error registering object {0}defined in '{1}' : {2}",
name == null ? string.Empty : string.Format("with name '{0}' ", name),
resourceDescription,
message),
rootCause)
@@ -257,4 +256,4 @@ namespace Spring.Objects.Factory
/// </summary>
protected string _objectName = string.Empty;
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <EFBFBD> 2002-2005 the original author or authors.
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -149,6 +149,9 @@ namespace Spring.Objects.Factory.Xml
/// </summary>
/// <param name="root">The root element to start parsing from.</param>
/// <param name="helper">The <see cref="ObjectDefinitionParserHelper"/> instance to use.</param>
/// <exception cref="ObjectDefinitionStoreException">
/// in case an error happens during parsing and registering object definitions
/// </exception>
protected virtual void ParseObjectDefinitions(XmlElement root, ObjectDefinitionParserHelper helper)
{
foreach (XmlNode node in root.ChildNodes)
@@ -156,34 +159,24 @@ namespace Spring.Objects.Factory.Xml
if (node.NodeType == XmlNodeType.Element)
{
XmlElement element = (XmlElement) node;
INamespaceParser parser = GetNamespaceParser(element, helper);
ParserContext parserContext = new ParserContext(helper.ReaderContext, helper);
parser.ParseElement(element, parserContext);
try
{
INamespaceParser parser = GetNamespaceParser(element, helper);
ParserContext parserContext = new ParserContext(helper.ReaderContext, helper);
parser.ParseElement(element, parserContext);
}
catch( ObjectDefinitionStoreException )
{
throw;
}
catch (Exception ex)
{
helper.ReaderContext.ReportException(node, null, "Failed parsing element", ex);
}
}
}
}
/// <summary>
/// Parses the default element.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="helper">The helper.</param>
private void ParseDefaultElement(XmlElement element, ObjectDefinitionParserHelper helper)
{
if (element.LocalName == ObjectDefinitionConstants.ImportElement)
{
ImportObjectDefinitionResource(element);
}
else if (element.LocalName == ObjectDefinitionConstants.AliasElement)
{
ParseAlias(element, ReaderContext.Registry);
}
else if (element.LocalName == ObjectDefinitionConstants.ObjectElement)
{
RegisterObjectDefinition(element, helper);
}
}
/// <summary>
/// Loads external XML object definitions from the resource described by the supplied
/// <paramref name="resource"/>.
@@ -337,4 +330,4 @@ namespace Spring.Objects.Factory.Xml
#endregion
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <EFBFBD> 2002-2005 the original author or authors.
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -278,9 +278,14 @@ namespace Spring.Objects.Factory.Xml
return;
}
}
catch(ObjectDefinitionStoreException)
{
throw;
}
catch (Exception ex)
{
throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
//throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
parserContext.ReaderContext.ReportException(element, null, null, ex);
}
@@ -340,6 +345,7 @@ namespace Spring.Objects.Factory.Xml
string objectName = id;
if (StringUtils.IsNullOrEmpty(objectName))
{
// TODO (EE): pass parserContext to CalculateId as well (resolving relative Urls in WebApps is parserContext-dependent) (EE)
objectName = CalculateId(element, aliases);
}
@@ -540,7 +546,7 @@ namespace Spring.Objects.Factory.Xml
typeName),
ex);
}
catch (ApplicationException ex)
catch (Exception ex)
{
parserContext.ReaderContext.ReportException(element, id, string.Empty, ex);
}
@@ -1433,4 +1439,4 @@ namespace Spring.Objects.Factory.Xml
return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring";
}
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <EFBFBD> 2002-2005 the original author or authors.
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -231,6 +231,10 @@ namespace Spring.Objects.Factory.Xml
"Line " + ex.LineNumber + " in XML document from " +
resource + " is invalid. " + ex.Message, ex);
}
catch(ObjectDefinitionStoreException)
{
throw;
}
catch (Exception ex)
{
throw new ObjectDefinitionStoreException("Unexpected exception parsing XML document from " + resource.Description + "Inner exception message= " + ex.Message, ex);

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <EFBFBD> 2002-2005 the original author or authors.
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ using System.Reflection;
using System.Runtime.Remoting;
using Common.Logging;
using Spring.Objects;
using Spring.Reflection.Dynamic;
#endregion
@@ -246,7 +247,9 @@ namespace Spring.Util
#endif
try
{
return constructor.Invoke(arguments);
// replaced with SafeConstructor() to avoid nasty "TargetInvocationException"s
//return constructor.Invoke(arguments);
return (new SafeConstructor(constructor)).Invoke(arguments);
}
catch (Exception ex)
{
@@ -542,4 +545,4 @@ namespace Spring.Util
return hashcode.ToString("X6");
}
}
}
}

View File

@@ -27,6 +27,7 @@ using System.Security.Policy;
using System.Xml;
using NUnit.Framework;
using Spring.Objects;
using Spring.Objects.Factory;
using Spring.Util;
#endregion
@@ -64,6 +65,48 @@ namespace Spring.Context.Support
Assert.AreEqual(1, ContextRegistry.GetContext().ObjectDefinitionCount);
}
[Test]
public void CreateRootContextFailure()
{
const string xmlData =
@"<context type='Spring.Context.Support.XmlApplicationContext, Spring.Core'>
<resource uri='assembly://Spring.Core.Tests/DoesNotExist.xml'/>
</context>";
CreateConfigurationElement(xmlData);
ContextHandler ctxHandler = new ContextHandler();
try
{
IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(null, null, configurationElement);
Assert.Fail("");
}
catch(ConfigurationException cfgex)
{
Assert.IsInstanceOfType( typeof(ObjectDefinitionStoreException), cfgex.InnerException );
}
}
[Test]
public void CreateChildContextFailure()
{
const string xmlData =
@"<context type='Spring.Context.Support.XmlApplicationContext, Spring.Core'>
<resource uri='assembly://Spring.Core.Tests/DoesNotExist.xml'/>
</context>";
CreateConfigurationElement(xmlData);
ContextHandler ctxHandler = new ContextHandler();
try
{
IApplicationContext ctx = (IApplicationContext) ctxHandler.Create(new StaticApplicationContext(), null, configurationElement);
Assert.Fail("");
}
catch(ConfigurationException cfgex)
{
Assert.IsInstanceOfType( typeof(ObjectDefinitionStoreException), cfgex.InnerException );
}
}
/// <summary>
/// Expect failure when using a type that does not inherit from IApplicationContext
/// </summary>

View File

@@ -0,0 +1,18 @@
using System.Xml;
using NUnit.Framework;
namespace Spring.Core.IO
{
/// <summary>
/// Summary description for ConfigSectionResourceTests.
/// </summary>
[TestFixture]
public class ConfigSectionResourceTests
{
[Test]
public void CanCreate()
{
// TODO
}
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name='spring'>
<section name='objects' type='Spring.Context.Support.DefaultSectionHandler, Spring.Core' />
</sectionGroup>
</configSections>
<spring>
<context type='Spring.Context.Support.XmlApplicationContext, Spring.Core' name='Parent'>
<resource uri='config://spring/objects' />
</context>
<objects xmlns='http://www.springframework.net'>
<object id='Parent' type='Spring.Objects.TestObject,Spring.Core.Tests'>
<property name='name' value='Parent' />
</object>
</objects>
</spring>
</configuration>

View File

@@ -33,7 +33,8 @@ namespace Spring.DataBinding
#if NET_2_0
private class BindToNullable_TestEntity
{
public Nullable<short> SortOrder { get;set; }
private Nullable<short> sortOrder;
public Nullable<short> SortOrder { get { return sortOrder; } set { sortOrder = value; } }
}
[Test(Description="http://jira.springframework.org/browse/SPRNET-996")]

View File

@@ -132,6 +132,11 @@
AssemblyName = "System.Windows.Forms"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Windows.Forms.dll"
/>
<Reference
Name = "System.Web"
AssemblyName = "System.Web"
HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Web.dll"
/>
</References>
</Build>
<Files>
@@ -192,6 +197,11 @@
RelPath = "TestResource.txt"
BuildAction = "EmbeddedResource"
/>
<File
RelPath = "TestResourceLoader.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Caching\AbstractCacheTests.cs"
SubType = "Code"
@@ -477,6 +487,15 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Core\IO\ConfigSectionResourceTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Core\IO\ConfigSectionResourceTests_config1.xml"
BuildAction = "EmbeddedResource"
/>
<File
RelPath = "Core\IO\ConfigurableResourceLoaderTests.cs"
SubType = "Code"

View File

@@ -232,6 +232,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Core\IO\AssemblyResourceTest.cs" />
<Compile Include="Core\IO\ConfigSectionResourceTests.cs" />
<Compile Include="Core\IO\ConfigurableResourceLoaderTests.cs" />
<Compile Include="Core\IO\FileSystemResourceCommonTests.cs" />
<Compile Include="Core\IO\FileSystemResourceTests.cs" />
@@ -655,6 +656,7 @@
<Compile Include="StreamHelperDecorator.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestResourceLoader.cs" />
<Compile Include="Threading\AsyncTestMethod.cs" />
<Compile Include="Threading\AsyncTestTask.cs" />
<Compile Include="Threading\CallContextStorageTests.cs" />
@@ -755,6 +757,7 @@
<EmbeddedResource Include="Context\Support\invalidType.xml" />
<EmbeddedResource Include="Core\TypeResolution\aliasedObjects.xml" />
<EmbeddedResource Include="Core\IO\TestResource.txt" />
<EmbeddedResource Include="Core\IO\ConfigSectionResourceTests_config1.xml" />
<Content Include="Data\PathMatcher\EmptyPattern.test" />
<Content Include="Data\PathMatcher\Examples.test" />
<Content Include="Data\PathMatcher\InBetween.test" />

View File

@@ -33,11 +33,14 @@
<include name="**/*.txt" />
<include name="**/*.vb" />
<include name="**/*.properties" />
<include name="**/*.xml" />
<!--
<include name="**/SimpleAppContext.xml" />
<include name="**/Factory/Attributes/*.xml" />
<include name="**/Context/Support/*.xml" />
<include name="**/aliasedObjects.xml" />
<include name="**/contextlifecycle.xml" />
-->
</resources>
<references basedir="${current.bin.dir}">
<include name="System.EnterpriseServices.dll" />

View File

@@ -0,0 +1,103 @@
using System;
using System.IO;
using System.Net;
using System.Web;
using System.Xml;
using NUnit.Framework;
namespace Spring
{
/// <summary>
/// Supports obtaining embedded resources from assembly.
/// </summary>
/// <remarks>
/// The first <c>context</c> argument is always the namespace scope to be used for resolving resource names.
/// </remarks>
public class TestResourceLoader
{
#region WebRequest
public class TestResourceWebResponse : WebResponse
{
private Type resourceType;
private string resourceName;
public TestResourceWebResponse(Uri requestUri)
{
string typeName = HttpUtility.UrlDecode(requestUri.AbsolutePath.Substring(1)); // strip leading '/'
resourceType = Type.GetType(typeName, true);
resourceName = HttpUtility.UrlDecode(requestUri.Fragment.Substring(1)); // strip leading '#'
}
public override System.IO.Stream GetResponseStream()
{
Stream stm = TestResourceLoader.GetStream(resourceType, resourceName);
return stm;
}
}
public class TestResourceWebRequest : WebRequest
{
private Uri requestUri;
public TestResourceWebRequest(Uri requestUri)
{
this.requestUri = requestUri;
}
public override WebResponse GetResponse()
{
return new TestResourceWebResponse(requestUri);
}
}
public class TestResourceWebRequestFactory : IWebRequestCreate
{
public WebRequest Create(Uri uri)
{
return new TestResourceWebRequest(uri);
}
}
#endregion
static TestResourceLoader()
{
WebRequest.RegisterPrefix("testres", new TestResourceWebRequestFactory());
}
private TestResourceLoader()
{}
public static Uri GetUri(object context, string ext)
{
string resname = context.GetType().AssemblyQualifiedName + "#" + ext;
Uri uri = new Uri("testres://(local)/" + resname, false);
return uri;
}
public static string GetText(object context, string ext)
{
Stream stm = GetStream(context, ext);
return new StreamReader(stm).ReadToEnd();
}
public static XmlDocument GetXml(object context, string ext)
{
Stream stm = GetStream(context, ext);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load( stm );
return xmlDoc;
}
public static Stream GetStream(object context, string ext)
{
Type contextType = (context is Type) ? (Type)context : context.GetType();
string resname = contextType.FullName + ext;
Stream stm = contextType.Assembly.GetManifestResourceStream(resname);
Assert.IsNotNull(stm, "Resource '{0}' in assembly '{1}' not found", resname, contextType.Assembly.FullName);
return stm;
}
}
}

View File

@@ -26,9 +26,11 @@ using System.Collections;
using System.Collections.Generic;
#endif
using System.Reflection;
using System.Runtime.Serialization;
using System.Security.Policy;
using NUnit.Framework;
using Spring.Objects;
using Spring.Objects.Factory;
using Spring.Util;
#endregion
@@ -116,6 +118,22 @@ namespace Spring.Util
Assert.IsNotNull(foo, "Failed to instantiate an instance of a valid Type.");
Assert.IsTrue(foo is TestObject, "The instantiated instance was not an instance of the type that was passed in.");
}
[Test]
public void InstantiateTypeThrowingWithinPublicConstructor()
{
try
{
ObjectUtils.InstantiateType(typeof(ThrowingWithinConstructor));
Assert.Fail();
}
catch(FatalReflectionException ex)
{
// no nasty "TargetInvocationException" is in between!
Assert.AreEqual( typeof(ThrowingWithinConstructorException), ex.InnerException.GetType() );
}
}
#if NET_2_0
[Test]
[ExpectedException(typeof(FatalReflectionException))]
@@ -348,6 +366,29 @@ namespace Spring.Util
private string _name;
}
[Serializable]
private class ThrowingWithinConstructorException : TestException
{
public ThrowingWithinConstructorException()
{}
public ThrowingWithinConstructorException(string message) : base(message)
{}
public ThrowingWithinConstructorException(string message, Exception inner) : base(message, inner)
{}
protected ThrowingWithinConstructorException(SerializationInfo info, StreamingContext context) : base(info, context)
{}
}
public class ThrowingWithinConstructor
{
public ThrowingWithinConstructor()
{
throw new ThrowingWithinConstructorException();
}
}
#endregion
}
}

View File

@@ -321,7 +321,7 @@
/>
<File
RelPath = "Web\Support\ControlInterceptionTests.cs"
SubType = "Code"
SubType = "ASPXCodeBehind"
BuildAction = "Compile"
/>
<File