SPRNETCODECONFIG-4 introduce support for explicit restriction on assembly load scanning scope

This commit is contained in:
Steve Bohlen
2013-01-13 19:39:07 -05:00
parent 5a0e1c483f
commit 59b37f6f74
5 changed files with 102 additions and 57 deletions

View File

@@ -24,6 +24,7 @@ using System.Linq;
using System.Reflection;
using Spring.Objects.Factory.Support;
using Spring.Stereotype;
using Spring.Util;
namespace Spring.Context.Attributes
{
@@ -39,17 +40,13 @@ namespace Spring.Context.Attributes
{
"Spring.",
"NHibernate.",
"Common.Logging.",
"Common.Logging",
"log4net",
"Quartz"
"Quartz",
"NVelocity",
"Rhino.Mocks"
};
//TODO: HACK -- required to permit testing since testing assy also starts with excluded name "Spring."
private readonly IList<string> _springAssemblyIncludeNames = new List<string>()
{
"Spring.Core.Tests"
};
private IObjectNameGenerator _objectNameGenerator = new AttributeObjectNameGenerator();
/// <summary>
@@ -148,13 +145,12 @@ namespace Spring.Context.Attributes
base.SetDefaultFilters();
//add the desired assembly exclusions to the list
_assemblyExclusionPredicates.Add(a => _springAssemblyExcludePrefixes.Any(n => n.StartsWith(a.GetName().Name)));
//_assemblyExclusionPredicates.Add(a => a.GetName().Name.StartsWith(_springAssemblyPrefix));
//_assemblyExclusionPredicates.Add(a => _springAssemblies.Contains(a.GetName().Name));
_assemblyExclusionPredicates.Add(a => a.GetName().Name.StartsWith("System."));
_assemblyExclusionPredicates.Add(a => a.GetName().Name.StartsWith("Microsoft."));
_assemblyExclusionPredicates.Add(a => a.GetName().Name == "mscorlib");
_assemblyExclusionPredicates.Add(a => a.GetName().Name == "System");
_assemblyExclusionPredicates.Add(assembly => _springAssemblyExcludePrefixes.Any(name => name.StartsWith(assembly.GetName().Name))
&& assembly.GetName().Name != "Spring.Core.Tests");
_assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name.StartsWith("System."));
_assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name.StartsWith("Microsoft."));
_assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name == "mscorlib");
_assemblyExclusionPredicates.Add(assembly => assembly.GetName().Name == "System");
}
/// <summary>
@@ -172,14 +168,39 @@ namespace Spring.Context.Attributes
/// </summary>
public AssemblyObjectDefinitionScanner()
{
//AssemblyLoadExclusionPredicates.Add(name => _springAssemblyExcludePrefixes.Any(n => name.StartsWith(n) && !name.Contains(".Tests")));
AssemblyLoadExclusionPredicates.Add(candidate => _springAssemblyExcludePrefixes.Any(excludeName => candidate.StartsWith(excludeName) && _springAssemblyIncludeNames.All(includeName => includeName != candidate)));
//AssemblyLoadExclusionPredicates.Add(name => _springAssemblies.Contains(name));
AssemblyLoadExclusionPredicates.Add(candidate => _springAssemblyExcludePrefixes.Any(candidate.StartsWith)
&& candidate != "Spring.Core.Tests");
AssemblyLoadExclusionPredicates.Add(name => name.StartsWith("System."));
AssemblyLoadExclusionPredicates.Add(name => name.StartsWith("Microsoft."));
AssemblyLoadExclusionPredicates.Add(name => name == "mscorlib");
AssemblyLoadExclusionPredicates.Add(name => name == "System");
}
/// <summary>
/// Initializes a new instance of the <see cref="AssemblyObjectDefinitionScanner"/> class.
/// </summary>
/// <param name="assembliesToIncludePredicates">The assemblies to include predicates.</param>
public AssemblyObjectDefinitionScanner(params Func<string, bool>[] assembliesToIncludePredicates)
{
//force exclude for ALL assemblies
AssemblyLoadExclusionPredicates.Add(name => true);
//since all assemblies are EXCLUDED above, these will be the ONLY assemblies to be loaded
foreach (var predicate in assembliesToIncludePredicates)
{
AssemblyLoadInclusionPredicates.Add(predicate);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="AssemblyObjectDefinitionScanner"/> class.
/// </summary>
/// <param name="assembliesToInclude">The names of assemblies to include.</param>
public AssemblyObjectDefinitionScanner(params string[] assembliesToInclude)
: this(name => assembliesToInclude.Any(candidate => candidate == name))
{
AssertUtils.ArgumentNotNull(assembliesToInclude, "assembliesToInclude");
}
}
}

View File

@@ -46,6 +46,11 @@ namespace Spring.Context.Attributes
/// </summary>
protected IList<Func<string, bool>> AssemblyLoadExclusionPredicates = new List<Func<string, bool>>();
/// <summary>
/// Names of Assemblies to include for scanning.
/// </summary>
protected IList<Func<string, bool>> AssemblyLoadInclusionPredicates = new List<Func<string, bool>>();
/// <summary>
/// Assembly Inclusion Predicates.
/// </summary>
@@ -81,11 +86,29 @@ namespace Spring.Context.Attributes
/// </summary>
protected DocumentDefaultsDefinition _defaults;
protected string _scanStartFolderPath;
/// <summary>
/// Stores the object default definitons defined in the XML configuration documnet
/// </summary>
public DocumentDefaultsDefinition Defaults { get { return _defaults; } set { _defaults = value; } }
public string ScanStartFolderPath
{
get
{
//if we have no value, set it to the current bin dir
if (string.IsNullOrEmpty(_scanStartFolderPath))
{
_scanStartFolderPath = GetCurrentBinDirectoryPath();
}
return _scanStartFolderPath;
}
set { _scanStartFolderPath = value; }
}
#region IAssemblyTypeScanner Members
/// <summary>
@@ -106,7 +129,7 @@ namespace Spring.Context.Attributes
/// <returns></returns>
public IAssemblyTypeScanner ExcludeType<T>()
{
TypeExclusionPredicates.Add(t => t.FullName == typeof (T).FullName);
TypeExclusionPredicates.Add(t => t.FullName == typeof(T).FullName);
return this;
}
@@ -117,7 +140,7 @@ namespace Spring.Context.Attributes
/// <returns></returns>
public IAssemblyTypeScanner IncludeType<T>()
{
TypeInclusionPredicates.Add(t => t.FullName == typeof (T).FullName);
TypeInclusionPredicates.Add(t => t.FullName == typeof(T).FullName);
return this;
}
@@ -145,7 +168,7 @@ namespace Spring.Context.Attributes
IList<Type> types = new List<Type>();
foreach (Assembly assembly in GetAllMatchingAssemblies())
foreach (Assembly assembly in GetAllMatchingAssemblies(ScanStartFolderPath))
{
TypeSources.Add(new AssemblyTypeSource(assembly));
}
@@ -225,23 +248,21 @@ namespace Spring.Context.Attributes
#endregion
private List<string> GetAllAssembliesInPath()
private List<string> GetAllAssembliesInPath(string folderPath)
{
string folderPath = GetCurrentBinDirectoryPath();
var assemblies = new List<string>();
assemblies.AddRange(DiscoverAssemblies(folderPath, "*.dll"));
assemblies.AddRange(DiscoverAssemblies(folderPath, "*.exe"));
Logger.Debug(m => m("Assemblies to be scanned: {0}", StringUtils.ArrayToCommaDelimitedString(assemblies.ToArray())));
return assemblies;
}
private IEnumerable<Assembly> GetAllMatchingAssemblies()
private IEnumerable<Assembly> GetAllMatchingAssemblies(string folderPath)
{
IEnumerable<string> assemblyCandidates = GetAllAssembliesInPath();
IEnumerable<string> assemblyCandidates = GetAllAssembliesInPath(folderPath);
IList<Assembly> assemblies = new List<Assembly>();
@@ -378,7 +399,10 @@ namespace Spring.Context.Attributes
{
string name = Path.GetFileNameWithoutExtension(file);
if (!AssemblyLoadExclusionPredicates.Any(exclude => exclude(name)))
bool isNotExcluded = !AssemblyLoadExclusionPredicates.Any(exclude => exclude(name));
bool isIncluded = AssemblyLoadInclusionPredicates.Any(include => include(name));
if (isNotExcluded || isIncluded)
{
assemblies.Add(file);
}

View File

@@ -23,6 +23,7 @@ using System;
using System.Reflection;
using Spring.Context.Attributes;
using Spring.Objects.Factory.Support;
using Spring.Util;
namespace Spring.Context.Support
{
@@ -54,9 +55,25 @@ namespace Spring.Context.Support
public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Func<Assembly, bool> assemblyPredicate,
Func<Type, bool> typePredicate)
{
//create a scanner instance using the scan path
var scanner = new AssemblyObjectDefinitionScanner();
Scan(context, assemblyScanPath, assemblyPredicate, typePredicate, new string[0]);
}
/// <summary>
/// Scans the specified context.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="assemblyScanPath">The assembly scan path.</param>
/// <param name="assemblyPredicate">The assembly predicate.</param>
/// <param name="typePredicate">The type predicate.</param>
/// <param name="assembliesToScan">The assemblies to scan.</param>
public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Func<Assembly, bool> assemblyPredicate, Func<Type, bool> typePredicate, params string[] assembliesToScan)
{
AssemblyObjectDefinitionScanner scanner =
ArrayUtils.HasElements(assembliesToScan) ? new AssemblyObjectDefinitionScanner(assembliesToScan) : new AssemblyObjectDefinitionScanner();
scanner.ScanStartFolderPath = assemblyScanPath;
//configure the scanner per the provided constraints
scanner.WithAssemblyFilter(assemblyPredicate).WithIncludeFilter(typePredicate);
@@ -105,6 +122,6 @@ namespace Spring.Context.Support
Scan(context, null, obj => true, typePredicate);
}
}
}

View File

@@ -66,7 +66,7 @@ namespace Spring.Context.Attributes
_scanner.IncludeType<TheConfigurationClass>();
_scanner.IncludeType<TheImportedConfigurationClass>();
_scanner.WithExcludeFilter(t => t.Name.StartsWith("TheImported"));
IEnumerable<Type> types = _scanner.Scan();
//Assert.That(types.Any(t => t.Name == "TheConfigurationClass"));
@@ -88,15 +88,6 @@ namespace Spring.Context.Attributes
Assert.That(types.Count(), Is.EqualTo(2));
}
[Serializable]
private class Scanner : AssemblyTypeScanner
{
protected override bool IsCompoundPredicateSatisfiedBy(Type type)
{
return IsIncludedType(type) && !IsExcludedType(type);
}
}
private AssemblyObjectDefinitionScanner _scanner;
private List<Func<Type, bool>> ExcludePredicates

View File

@@ -30,12 +30,14 @@ namespace Spring.Context.Support
public class CodeConfigApplicationContextTests
{
private CodeConfigApplicationContext _context;
private AssemblyObjectDefinitionScanner _scanner;
[SetUp]
public void _TestSetup()
{
_context = new CodeConfigApplicationContext();
}
_scanner = new AssemblyObjectDefinitionScanner();
}
[Test]
public void Can_Filter_For_Assembly_Based_On_Assembly_Metadata()
@@ -47,18 +49,16 @@ namespace Spring.Context.Support
}
[Test]
[Ignore]
public void Can_Filter_For_Assembly_Containing_Specific_Type_But_Having_NO_Definitions()
{
//specifically filter assemblies for one that we *know* will result in NO [Configuration] types in it
_context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(Spring.Core.IOrdered).Name)));
_context.Refresh();
_context.Refresh();
Assert.That(_context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(4));
}
[Test]
[Ignore]
public void Can_Filter_For_Assembly_Containing_Specific_Type()
{
_context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(MarkerTypeForScannerToFind).Name)));
@@ -88,24 +88,15 @@ namespace Spring.Context.Support
[Test]
public void Can_Filter_For_Specific_Types_With_Multiple_Include_Filters()
{
var scanner = new AssemblyObjectDefinitionScanner();
scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name));
scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheConfigurationClass).Name));
_scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name));
_scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheConfigurationClass).Name));
_context.Scan(scanner);
_context.Scan(_scanner);
_context.Refresh();
AssertExpectedObjectsAreRegisteredWith(_context, 19);
}
[Test]
public void Scanner()
{
AssemblyObjectDefinitionScanner scanner = new AssemblyObjectDefinitionScanner();
scanner.AssemblyHavingType<TheConfigurationClass>();
}
[Test]
public void Can_Perform_Scan_With_No_Filtering()
{
@@ -137,6 +128,7 @@ namespace Spring.Context.Support
}
//DO NOT DELETE: this empty class req'd by the scanning tests!
public class MarkerTypeForScannerToFind
{