Components registration - package scanning
This commit is contained in:
parent
0c23f613d6
commit
6d0753c7a8
11 changed files with 169 additions and 2 deletions
1
TODO
1
TODO
|
@ -1,6 +1,5 @@
|
||||||
To Do:
|
To Do:
|
||||||
* Implement "DriverFor" support
|
* Implement "DriverFor" support
|
||||||
* Scanning packages for annotated components
|
|
||||||
* General usage documentation
|
* General usage documentation
|
||||||
* Uncouple component-provided names from the library
|
* Uncouple component-provided names from the library
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package info.ebenoit.ebul.cmp;
|
package info.ebenoit.ebul.cmp;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -15,7 +16,9 @@ import info.ebenoit.ebul.func.ThrowingBiConsumer;
|
||||||
import info.ebenoit.ebul.func.ThrowingConsumer;
|
import info.ebenoit.ebul.func.ThrowingConsumer;
|
||||||
import info.ebenoit.ebul.func.ThrowingSupplier;
|
import info.ebenoit.ebul.func.ThrowingSupplier;
|
||||||
import info.ebenoit.ebul.reflection.Annotations;
|
import info.ebenoit.ebul.reflection.Annotations;
|
||||||
|
import info.ebenoit.ebul.reflection.Classes;
|
||||||
import info.ebenoit.ebul.reflection.MemberFinder;
|
import info.ebenoit.ebul.reflection.MemberFinder;
|
||||||
|
import info.ebenoit.ebul.reflection.PackageScanner;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,6 +58,39 @@ public final class NewComponentInfo< T >
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a package for classes that correspond to annotated components and processes them using
|
||||||
|
* {@link #fromClass(Class)}
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the name of the package to scan
|
||||||
|
* @param recursive
|
||||||
|
* <code>true</code> if child packages are to be scanned as well
|
||||||
|
* @return the list of component registration records
|
||||||
|
* @throws IOException
|
||||||
|
* if an I/O error occurs while scanning the packages
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* if one of the classes cannot be loaded
|
||||||
|
* @throws ComponentDefinitionException
|
||||||
|
* if one of the loaded definitions is invalid
|
||||||
|
*/
|
||||||
|
public static ArrayList< NewComponentInfo< ? > > scanPackage( final String name , final boolean recursive )
|
||||||
|
throws IOException , ClassNotFoundException , ComponentDefinitionException
|
||||||
|
{
|
||||||
|
final PackageScanner packageScanner = new PackageScanner( name , recursive );
|
||||||
|
final ArrayList< Class< ? > > classes = packageScanner.findClasses( //
|
||||||
|
c -> ( ( c.getModifiers( ) & ( Modifier.ABSTRACT | Modifier.INTERFACE ) ) == 0
|
||||||
|
&& Classes.hasAncestorMatching( c , x -> x.isAnnotationPresent( Component.class ) , true ) ) );
|
||||||
|
|
||||||
|
final ArrayList< NewComponentInfo< ? > > results = new ArrayList< >( );
|
||||||
|
final int n = classes.size( );
|
||||||
|
for ( int i = 0 ; i < n ; i++ ) {
|
||||||
|
results.add( NewComponentInfo.fromClass( classes.get( i ) ) );
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new component information record based on a component's annotated class.
|
* Creates a new component information record based on a component's annotated class.
|
||||||
*
|
*
|
||||||
|
@ -540,7 +576,7 @@ public final class NewComponentInfo< T >
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
ThrowingBiConsumer< Object , Object > ci = (ThrowingBiConsumer< Object , Object >) injector;
|
final ThrowingBiConsumer< Object , Object > ci = (ThrowingBiConsumer< Object , Object >) injector;
|
||||||
injectors.add( ci );
|
injectors.add( ci );
|
||||||
|
|
||||||
this.dependencies.add( dependency );
|
this.dependencies.add( dependency );
|
||||||
|
|
|
@ -5,12 +5,20 @@ import org.junit.Test;
|
||||||
|
|
||||||
import info.ebenoit.ebul.func.ThrowingBiConsumer;
|
import info.ebenoit.ebul.func.ThrowingBiConsumer;
|
||||||
import info.ebenoit.ebul.func.ThrowingConsumer;
|
import info.ebenoit.ebul.func.ThrowingConsumer;
|
||||||
|
import test.inherited.CBase;
|
||||||
|
import test.inherited.CChild;
|
||||||
|
import test.inherited.CChildOfAbstract;
|
||||||
|
import test.interfaces.CImplementation;
|
||||||
|
import test.simple.CSimple;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -889,4 +897,51 @@ public class TestNewComponentInfo
|
||||||
injector.accept( cmp , inject );
|
injector.accept( cmp , inject );
|
||||||
assertSame( inject , cmp.dependency );
|
assertSame( inject , cmp.dependency );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: {@link NewComponentInfo#scanPackage(String, boolean)} finds a simple {@link Component}-annotated class
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testScanPackageSimple( )
|
||||||
|
throws ComponentDefinitionException , ClassNotFoundException , IOException
|
||||||
|
{
|
||||||
|
ArrayList< NewComponentInfo< ? > > result = NewComponentInfo.scanPackage( "test.simple" , false );
|
||||||
|
assertEquals( 1 , result.size( ) );
|
||||||
|
assertSame( CSimple.class , result.get( 0 ).getSupplier( ).get( ).getClass( ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: {@link NewComponentInfo#scanPackage(String, boolean)} finds components that inherit each other, ignoring
|
||||||
|
* abstract classes
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testScanPackageInheritance( )
|
||||||
|
throws ComponentDefinitionException , ClassNotFoundException , IOException
|
||||||
|
{
|
||||||
|
ArrayList< NewComponentInfo< ? > > result = NewComponentInfo.scanPackage( "test.inherited" , false );
|
||||||
|
assertEquals( 3 , result.size( ) );
|
||||||
|
|
||||||
|
Set< ? > classes = result.stream( ).map( x -> x.getSupplier( ).get( ).getClass( ) )
|
||||||
|
.collect( Collectors.toSet( ) );
|
||||||
|
assertTrue( classes.contains( CBase.class ) );
|
||||||
|
assertTrue( classes.contains( CChild.class ) );
|
||||||
|
assertTrue( classes.contains( CChildOfAbstract.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: {@link NewComponentInfo#scanPackage(String, boolean)} finds components defined by implementing a
|
||||||
|
* {@link Component}-annotated interface
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testScanPackageInterfaces( )
|
||||||
|
throws ComponentDefinitionException , ClassNotFoundException , IOException
|
||||||
|
{
|
||||||
|
ArrayList< NewComponentInfo< ? > > result = NewComponentInfo.scanPackage( "test.interfaces" , false );
|
||||||
|
assertEquals( 1 , result.size( ) );
|
||||||
|
|
||||||
|
assertSame( CImplementation.class , result.get( 0 ).getSupplier( ).get( ).getClass( ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
9
src/test/java/test/inherited/CAbstractBase.java
Normal file
9
src/test/java/test/inherited/CAbstractBase.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package test.inherited;
|
||||||
|
|
||||||
|
import info.ebenoit.ebul.cmp.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public abstract class CAbstractBase
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
8
src/test/java/test/inherited/CAbstractChild.java
Normal file
8
src/test/java/test/inherited/CAbstractChild.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package test.inherited;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class CAbstractChild
|
||||||
|
extends CBase
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
12
src/test/java/test/inherited/CBase.java
Normal file
12
src/test/java/test/inherited/CBase.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package test.inherited;
|
||||||
|
|
||||||
|
|
||||||
|
import info.ebenoit.ebul.cmp.Component;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class CBase
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
8
src/test/java/test/inherited/CChild.java
Normal file
8
src/test/java/test/inherited/CChild.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package test.inherited;
|
||||||
|
|
||||||
|
|
||||||
|
public class CChild
|
||||||
|
extends CBase
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
8
src/test/java/test/inherited/CChildOfAbstract.java
Normal file
8
src/test/java/test/inherited/CChildOfAbstract.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package test.inherited;
|
||||||
|
|
||||||
|
|
||||||
|
public class CChildOfAbstract
|
||||||
|
extends CAbstractBase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
8
src/test/java/test/interfaces/CImplementation.java
Normal file
8
src/test/java/test/interfaces/CImplementation.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package test.interfaces;
|
||||||
|
|
||||||
|
|
||||||
|
public class CImplementation
|
||||||
|
implements CInterface
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
12
src/test/java/test/interfaces/CInterface.java
Normal file
12
src/test/java/test/interfaces/CInterface.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package test.interfaces;
|
||||||
|
|
||||||
|
|
||||||
|
import info.ebenoit.ebul.cmp.Component;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public interface CInterface
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
12
src/test/java/test/simple/CSimple.java
Normal file
12
src/test/java/test/simple/CSimple.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package test.simple;
|
||||||
|
|
||||||
|
|
||||||
|
import info.ebenoit.ebul.cmp.Component;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class CSimple
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
Loading…
Reference in a new issue