throw ArgumentException if no config location is passed into XmlApplicationContext 
always create DynamicMethod with "skipVisibility=true"
fixed bug introduced with the object definition's "scope" property when configuring prototypes in webapps
This commit is contained in:
eeichinger
2009-07-22 23:42:01 +00:00
parent f269366cb1
commit b72a4eda8d
14 changed files with 256 additions and 94 deletions

View File

@@ -143,22 +143,31 @@ namespace Spring.Objects.Factory.Config
/// <summary>
/// The default placeholder prefix.
/// </summary>
public const string DefaultPlaceholderPrefix = "${";
public static readonly string DefaultPlaceholderPrefix = "${";
/// <summary>
/// The default placeholder suffix.
/// </summary>
public const string DefaultPlaceholderSuffix = "}";
public static readonly string DefaultPlaceholderSuffix = "}";
private readonly ILog logger;
private ILog logger = LogManager.GetLogger(typeof (PropertyPlaceholderConfigurer));
private bool ignoreUnresolvablePlaceholders = false;
private string placeholderPrefix = DefaultPlaceholderPrefix;
private string placeholderSuffix = DefaultPlaceholderSuffix;
private EnvironmentVariableMode environmentVariableMode = EnvironmentVariableMode.Fallback;
/// <summary>
/// Initializes the new instance
/// </summary>
public PropertyPlaceholderConfigurer()
{
logger = LogManager.GetLogger(this.GetType());
}
#region Properties
#region Properties
/// <summary>
/// The placeholder prefix (the default is <c>${</c>).
/// </summary>

View File

@@ -77,11 +77,11 @@ namespace Spring.Objects.Factory.Config
/// The default configuration section name to use if none is explictly supplied.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.Config.PropertyResourceConfigurer.ConfigSections"/>
public const string DefaultConfigSectionName = "spring-config";
public static readonly string DefaultConfigSectionName = "spring-config";
#region Fields
private static readonly ILog _log = LogManager.GetLogger(typeof(PropertyResourceConfigurer));
private readonly ILog _log;
private int _order = Int32.MaxValue; // default: same as non-Ordered
private NameValueCollection _defaultProperties;
@@ -107,6 +107,7 @@ namespace Spring.Objects.Factory.Config
/// </remarks>
protected PropertyResourceConfigurer()
{
_log = LogManager.GetLogger(this.GetType());
}
#endregion

View File

@@ -266,8 +266,8 @@ namespace Spring.Objects.Factory.Support
{
AssertUtils.ArgumentNotNull(value, "Scope");
this.scope = value;
this.isSingleton = 0==string.Compare(SCOPE_SINGLETON, value, true);
this.isPrototype = 0==string.Compare(SCOPE_PROTOTYPE, value, true);
this.isPrototype = 0 == string.Compare(SCOPE_PROTOTYPE, value, true);
this.isSingleton = !isPrototype; // 0 == string.Compare(SCOPE_SINGLETON, value, true);
}
}

View File

@@ -291,7 +291,7 @@ namespace Spring.Reflection.Dynamic
{
AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value.");
bool skipVisibility = !IsPublic(fieldInfo);
bool skipVisibility = true; //!IsPublic(fieldInfo);
Type[] argumentTypes = new Type[] { typeof(object) };
System.Reflection.Emit.DynamicMethod dmGetter = CreateDynamicMethod("get_" + fieldInfo.Name, typeof(object), argumentTypes, fieldInfo, skipVisibility);
ILGenerator il = dmGetter.GetILGenerator();
@@ -312,7 +312,7 @@ namespace Spring.Reflection.Dynamic
{
AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value.");
bool skipVisibility = !IsPublic(fieldInfo);
bool skipVisibility = true; // !IsPublic(fieldInfo);
System.Reflection.Emit.DynamicMethod dmSetter = CreateDynamicMethod("set_" + fieldInfo.Name, null, new Type[] { typeof(object), typeof(object) }, fieldInfo, skipVisibility);
ILGenerator il = dmSetter.GetILGenerator();
EmitFieldSetter(il, fieldInfo, false);
@@ -333,7 +333,7 @@ namespace Spring.Reflection.Dynamic
AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value.");
MethodInfo getMethod = propertyInfo.GetGetMethod();
bool skipVisibility = (null == getMethod || !IsPublic(getMethod)); // getter is public
bool skipVisibility = true; // (null == getMethod || !IsPublic(getMethod)); // getter is public
NetDynamicMethod dm = CreateDynamicMethod("get_" + propertyInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, propertyInfo, skipVisibility);
ILGenerator il = dm.GetILGenerator();
EmitPropertyGetter(il, propertyInfo, false);
@@ -354,7 +354,7 @@ namespace Spring.Reflection.Dynamic
AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value.");
MethodInfo setMethod = propertyInfo.GetSetMethod();
bool skipVisibility = (null == setMethod || !IsPublic(setMethod)); // setter is public
bool skipVisibility = true; // (null == setMethod || !IsPublic(setMethod)); // setter is public
Type[] argumentTypes = new Type[] { typeof(object), typeof(object), typeof(object[]) };
NetDynamicMethod dm = CreateDynamicMethod("set_" + propertyInfo.Name, null, argumentTypes, propertyInfo, skipVisibility);
ILGenerator il = dm.GetILGenerator();
@@ -371,7 +371,7 @@ namespace Spring.Reflection.Dynamic
{
AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a delegate for a null value.");
bool skipVisibility = !IsPublic(methodInfo);
bool skipVisibility = true; // !IsPublic(methodInfo);
NetDynamicMethod dm = CreateDynamicMethod(methodInfo.Name, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo, skipVisibility);
ILGenerator il = dm.GetILGenerator();
EmitInvokeMethod(il, methodInfo, false);
@@ -387,7 +387,7 @@ namespace Spring.Reflection.Dynamic
{
AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value.");
bool skipVisibility = !IsPublic(constructorInfo);
bool skipVisibility = true; //!IsPublic(constructorInfo);
System.Reflection.Emit.DynamicMethod dmGetter;
Type[] argumentTypes = new Type[] { typeof(object[]) };
dmGetter = CreateDynamicMethod(constructorInfo.Name, typeof(object), argumentTypes, constructorInfo, skipVisibility);
@@ -408,7 +408,7 @@ namespace Spring.Reflection.Dynamic
private static NetDynamicMethod CreateDynamicMethod(string methodName, Type returnType, Type[] argumentTypes, MemberInfo member, bool skipVisibility)
{
NetDynamicMethod dmGetter = null;
methodName = "_dynamic_" + member.DeclaringType.Name + "." + methodName;
methodName = "_dynamic_" + member.DeclaringType.FullName + "." + methodName;
try
{
new PermissionSet(PermissionState.Unrestricted).Demand();
@@ -425,68 +425,84 @@ namespace Spring.Reflection.Dynamic
{
NetDynamicMethod dm;
dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.Module, skipVisibility);
// if (member is FieldInfo)
// {
// // workaround for DynamicMethod bug not invoking type initializer before accessing static field
// // it seems all works correct if the DM is created with limited accessibility
// bool isStatic = (((FieldInfo) member).IsStatic);
// if (isStatic)
// {
// new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).PermitOnly();
// }
// dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.DeclaringType, true);
// if (isStatic)
// {
// CodeAccessPermission.RevertPermitOnly();
// }
// }
// else
// {
// dm = new NetDynamicMethod(methodName, returnType, argumentTypes, member.DeclaringType, true);
// }
return dm;
}
private static bool IsPublic(MemberInfo member)
{
if (member == null) return true;
/* TODO (EE): I am not sure, if "skipVisibility" in "CreateDynamicMethodInternal" may be true all the time or if visibility needs to be calculated like below
*
private static bool IsPublic(MemberInfo member)
{
if (member == null) return true;
switch(member.MemberType)
{
case MemberTypes.Event:
switch(member.MemberType)
{
bool isPublic = ((EventInfo) member).GetAddMethod() != null;
return isPublic && IsPublic(member.DeclaringType);
case MemberTypes.Event:
{
bool isPublic = ((EventInfo) member).GetAddMethod() != null;
return isPublic && IsPublic(member.DeclaringType);
}
case MemberTypes.Field:
{
bool isPublic = ((FieldInfo)member).IsPublic;
return isPublic && IsPublic(member.DeclaringType);
}
case MemberTypes.Property:
{
throw new NotSupportedException();
}
case MemberTypes.Constructor:
case MemberTypes.Method:
{
MethodBase methodBase = ((MethodBase)member);
bool isPublic = methodBase.IsPublic;
if (!isPublic)
{
return false;
}
if (!IsPublic(methodBase.DeclaringType))
{
return false;
}
if (member.MemberType == MemberTypes.Method
&& !IsPublic(((MethodInfo)methodBase).ReturnType))
{
return false;
}
foreach(ParameterInfo arg in methodBase.GetParameters())
{
if (!IsPublic(arg.ParameterType)) return false;
}
return true;
}
case MemberTypes.NestedType:
case MemberTypes.TypeInfo:
{
Type type = (Type)member;
bool isPublic = type.IsPublic;
if (type.IsNested && !IsPublic(type.DeclaringType))
{
return false;
}
#if NET_2_0
if (type.IsGenericType)
{
foreach(Type genericTypeArg in type.GetGenericArguments())
{
if (!IsPublic(genericTypeArg))
{
return false;
}
}
}
#endif
return true;
}
default:
throw new NotSupportedException();
}
case MemberTypes.Field:
{
bool isPublic = ((FieldInfo)member).IsPublic;
return isPublic && IsPublic(member.DeclaringType);
}
case MemberTypes.Property:
{
throw new NotSupportedException();
}
case MemberTypes.Constructor:
case MemberTypes.Method:
{
bool isPublic = ((MethodBase)member).IsPublic;
return isPublic && IsPublic(member.DeclaringType);
}
case MemberTypes.NestedType:
{
bool isPublic = ((Type)member).IsPublic;
return isPublic && IsPublic(member.DeclaringType);
}
case MemberTypes.TypeInfo:
{
bool isPublic = ((Type)member).IsPublic;
return isPublic;
}
default:
throw new NotSupportedException();
}
}
}
*/
#endif
#region Shared Code Generation

View File

@@ -361,8 +361,7 @@ namespace Spring.Objects.Factory.Support
/// </remarks>
protected override void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance)
{
if (objectDefinition is IWebObjectDefinition
&& ((IWebObjectDefinition)objectDefinition).Scope != ObjectScope.Application)
if (IsWebScopedSingleton(objectDefinition))
{
ObjectScope scope = ((IWebObjectDefinition) objectDefinition).Scope;
if (scope == ObjectScope.Request)
@@ -395,8 +394,7 @@ namespace Spring.Objects.Factory.Support
/// </remarks>
protected override void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition)
{
if (objectDefinition is IWebObjectDefinition
&& ((IWebObjectDefinition)objectDefinition).Scope != ObjectScope.Application)
if (IsWebScopedSingleton(objectDefinition))
{
ObjectScope scope = ((IWebObjectDefinition) objectDefinition).Scope;
if (scope == ObjectScope.Request)
@@ -409,7 +407,7 @@ namespace Spring.Objects.Factory.Support
}
else
{
throw new ObjectDefinitionException("Web singleton objects must be either request, session or application scoped.");
throw new ObjectDefinitionException("Web singleton objects must be either 'request' or 'session' scoped.");
}
}
else
@@ -418,6 +416,17 @@ namespace Spring.Objects.Factory.Support
}
}
private bool IsWebScopedSingleton(IObjectDefinition objectDefinition)
{
if (objectDefinition.IsSingleton
&& objectDefinition is IWebObjectDefinition)
{
ObjectScope scope = ((IWebObjectDefinition) objectDefinition).Scope;
return (scope == ObjectScope.Request) || (scope == ObjectScope.Session);
}
return false;
}
/// <summary>
/// Configures object instance by injecting dependencies, satisfying Spring lifecycle
/// interfaces and applying object post-processors.

View File

@@ -85,16 +85,23 @@ namespace Spring.Objects.Factory.Xml
if (webDefinition != null)
{
webDefinition.Scope = GetScope(element.GetAttribute(ObjectDefinitionConstants.ScopeAttribute));
if (definition.IsSingleton
&& element.HasAttribute(ObjectDefinitionConstants.ScopeAttribute))
{
webDefinition.Scope = GetScope(element.GetAttribute(ObjectDefinitionConstants.ScopeAttribute));
}
// force request and session scoped objects to be lazily initialized...
if (webDefinition.Scope != ObjectScope.Application)
if (webDefinition.Scope == ObjectScope.Request
|| webDefinition.Scope == ObjectScope.Session)
{
definition.IsLazyInit = true;
}
string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
if (typeName.EndsWith(".ascx") || typeName.EndsWith(".master"))
// string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
string typeName = definition.ObjectTypeName;
if (typeName != null
&& (typeName.EndsWith(".ascx") || typeName.EndsWith(".master")))
{
definition.IsAbstract = true;
}

View File

@@ -40,13 +40,13 @@ namespace Spring.Aspects.Cache
[TestFixture]
public sealed class CacheAspectIntegrationTests
{
private IApplicationContext context;
private GenericApplicationContext context;
private CacheAspect cacheAspect;
[SetUp]
public void SetUp()
{
context = new XmlApplicationContext();
context = new GenericApplicationContext();
cacheAspect = new CacheAspect();
cacheAspect.ApplicationContext = context;
@@ -56,7 +56,7 @@ namespace Spring.Aspects.Cache
public void TestCaching()
{
ICache cache = new NonExpiringCache();
((IConfigurableApplicationContext)context).ObjectFactory.RegisterSingleton("inventors", cache);
context.ObjectFactory.RegisterSingleton("inventors", cache);
ProxyFactory pf = new ProxyFactory(new InventorStore());
pf.AddAdvisors(cacheAspect);
@@ -87,7 +87,7 @@ namespace Spring.Aspects.Cache
public void UseMethodInfoForKeyGeneration()
{
ICache cache = new NonExpiringCache();
((IConfigurableApplicationContext)context).ObjectFactory.RegisterSingleton("defaultCache", cache);
context.ObjectFactory.RegisterSingleton("defaultCache", cache);
ProxyFactory pf = new ProxyFactory(new GenericDao<string, int>());
pf.AddAdvisors(cacheAspect);

View File

@@ -81,6 +81,13 @@ namespace Spring.Context.Support
}
}
[Test]
[ExpectedException(typeof(ArgumentException))]
public void NoConfigLocation()
{
new XmlApplicationContext();
}
[Test]
public void SingleConfigLocation()
{

View File

@@ -19,6 +19,7 @@
#endregion
using System;
using System.Collections;
using NUnit.Framework;
#if NET_2_0
using System.Collections.Generic;
@@ -33,6 +34,32 @@ namespace Spring.Objects.Factory.Support
public class ManagedDictionaryTests
{
#if NET_2_0
internal class InternalType
{
public string Value = "OK";
}
[Test]
public void ResolvesInternalGenericTypes()
{
ManagedDictionary dict2 = new ManagedDictionary();
dict2.Add("1", "stringValue");
dict2.KeyTypeName = "int";
dict2.ValueTypeName = typeof(InternalType).FullName;
IDictionary resolved = (IDictionary) dict2.Resolve("other", new RootObjectDefinition(typeof (object)), "prop",
delegate(string name, RootObjectDefinition definition, string argumentName, object element)
{
if ("stringValue".Equals(element))
{
return new InternalType();
}
return element;
}
);
Assert.AreEqual( typeof(InternalType), resolved[1].GetType() );
}
[Test]
public void ResolvesGenericTypeNames()
{
@@ -41,12 +68,18 @@ namespace Spring.Objects.Factory.Support
dict.KeyTypeName = "string";
dict.ValueTypeName = "System.Collections.Generic.List<[string]>";
dict.Resolve("somename", new RootObjectDefinition(typeof (object)), "prop",
delegate(string name, RootObjectDefinition definition, string argumentName, object element)
{
return new List<string>();
}
);
IDictionary resolved = (IDictionary) dict.Resolve("somename", new RootObjectDefinition(typeof(object)), "prop",
delegate(string name, RootObjectDefinition definition, string argumentName, object element)
{
if ("value".Equals(element))
{
return new List<string>();
}
return element;
}
);
Assert.AreEqual(1, resolved.Count);
Assert.AreEqual(typeof(List<string>), resolved["key"].GetType());
}
#endif
}

View File

@@ -275,5 +275,39 @@ namespace Spring.Objects.Factory.Xml
NamespaceParserRegistry.Reset();
}
}
[Test]
public void ParsesObjectAttributes()
{
DefaultListableObjectFactory of = new DefaultListableObjectFactory();
XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(of);
reader.LoadObjectDefinitions(new StringResource(
@"<?xml version='1.0' encoding='UTF-8' ?>
<objects xmlns='http://www.springframework.net'>
<object id='test1' type='Spring.Objects.TestObject, Spring.Core.Tests' singleton='false' abstract='true' />
<object id='test2' type='Spring.Objects.TestObject, Spring.Core.Tests' singleton='true' abstract='false' lazy-init='true'
autowire='no' dependency-check='simple'
depends-on='test1'
init-method='init'
destroy-method='destroy'
/>
</objects>
"));
AbstractObjectDefinition od1 = (AbstractObjectDefinition) of.GetObjectDefinition("test1");
Assert.IsFalse(od1.IsSingleton);
Assert.IsTrue(od1.IsAbstract);
Assert.IsFalse(od1.IsLazyInit);
AbstractObjectDefinition od2 = (AbstractObjectDefinition) of.GetObjectDefinition("test2");
Assert.IsTrue(od2.IsSingleton);
Assert.IsFalse(od2.IsAbstract);
Assert.IsTrue(od2.IsLazyInit);
Assert.AreEqual(AutoWiringMode.No, od2.AutowireMode);
Assert.AreEqual("init", od2.InitMethodName);
Assert.AreEqual("destroy", od2.DestroyMethodName);
Assert.AreEqual(1, od2.DependsOn.Length);
Assert.AreEqual("test1", od2.DependsOn[0]);
Assert.AreEqual(DependencyCheckingMode.Simple, od2.DependencyCheck);
}
}
}

View File

@@ -24,6 +24,7 @@ using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using NUnit.Framework;
using Spring.Context.Support;
using Spring.Util;
@@ -81,7 +82,46 @@ namespace Spring.Reflection.Dynamic
}
#endregion
#if NET_2_0
private void RespectsPermissionsPrivateMethod() {}
public void RespectsPermissionsPublicMethod() {}
[Test]
public void CanCreateWithRestrictedPermissions()
{
SecurityTemplate.MediumTrustInvoke(new ThreadStart(CanCreateWithRestrictedPermissionsImpl));
}
private void CanCreateWithRestrictedPermissionsImpl()
{
MethodInfo method = this.GetType().GetMethod("RespectsPermissionsPublicMethod");
IDynamicMethod m = DynamicMethod.Create(method);
m.Invoke(this, null);
}
[Test]
public void CanCreatePrivateMethodButThrowsOnInvoke()
{
SecurityTemplate.MediumTrustInvoke(new ThreadStart(CanCreatePrivateMethodButThrowsOnInvokeImpl));
}
private void CanCreatePrivateMethodButThrowsOnInvokeImpl()
{
MethodInfo privateMethod = this.GetType().GetMethod("RespectsPermissionsPrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
IDynamicMethod m = DynamicMethod.Create(privateMethod);
try
{
m.Invoke(this, null);
Assert.Fail();
}
catch(MethodAccessException)
{}
}
#endif
[Test]
public void TestInstanceMethods()
{

View File

@@ -295,7 +295,7 @@ namespace Spring
}
if (trustSection.Level == "Full")
{
{
return null;
}

View File

@@ -141,6 +141,12 @@ namespace Spring.Util
{
ObjectUtils.InstantiateType(typeof(Dictionary<,>));
}
[Test]
public void InstantiateGenericTypeWithArguments()
{
// ObjectUtils.InstantiateType(typeof(Dictionary<string, int>), new object[] { new object() } );
}
#endif
[Test]

View File

@@ -54,7 +54,7 @@ namespace Spring.Web.Support
IApplicationContext appContext =
new XmlApplicationContext(AbstractApplicationContext.DefaultRootContextName, false, RES_OBJECTS);
ContextRegistry.RegisterContext(appContext);
appContext = new XmlApplicationContext("/controls/", false, appContext);
appContext = new GenericApplicationContext("/controls/", false, appContext);
ContextRegistry.RegisterContext(appContext);
}