SPRNETCODECONFIG-4 introduce support for explicit restriction on assembly load scanning scope
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user