Component registration info - Lifecycle method finder rewritten
The method that looks for lifecycle methods now uses MemberFinder to locate lifecycle methods in both interfaces and superclasses.
This commit is contained in:
parent
aa3ee13f66
commit
a95d71e770
1 changed files with 58 additions and 50 deletions
|
@ -7,6 +7,7 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
@ -28,12 +29,19 @@ public final class NewComponentInfo< T >
|
||||||
{
|
{
|
||||||
/** Member finder that looks for the default constructor */
|
/** Member finder that looks for the default constructor */
|
||||||
private static final MemberFinder< Constructor< ? > > CONSTRUCTOR_FINDER;
|
private static final MemberFinder< Constructor< ? > > CONSTRUCTOR_FINDER;
|
||||||
|
/** Member finder that looks for lifecycle methods */
|
||||||
|
private static final MemberFinder< Method > LC_METHOD_FINDER;
|
||||||
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CONSTRUCTOR_FINDER = new MemberFinder< >( ( final Class< ? > c ) -> c.getDeclaredConstructors( ) , false );
|
CONSTRUCTOR_FINDER = new MemberFinder< >( ( final Class< ? > c ) -> c.getDeclaredConstructors( ) , false );
|
||||||
NewComponentInfo.CONSTRUCTOR_FINDER
|
NewComponentInfo.CONSTRUCTOR_FINDER
|
||||||
.setMemberFilter( ( final Constructor< ? > c ) -> c.getParameterCount( ) == 0 );
|
.setMemberFilter( ( final Constructor< ? > c ) -> c.getParameterCount( ) == 0 );
|
||||||
|
|
||||||
|
LC_METHOD_FINDER = new MemberFinder< >( MemberFinder.METHOD_EXTRACTOR , true );
|
||||||
|
NewComponentInfo.LC_METHOD_FINDER.setClassesFirst( true );
|
||||||
|
NewComponentInfo.LC_METHOD_FINDER
|
||||||
|
.setMemberFilter( m -> m.getDeclaredAnnotation( LifecycleMethod.class ) != null );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +86,7 @@ public final class NewComponentInfo< T >
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicit dependencies
|
// Explicit dependencies
|
||||||
for ( Class< ? super T > c : Annotations.findParentsWith( klass , Dependencies.class ) ) {
|
for ( final Class< ? super T > c : Annotations.findParentsWith( klass , Dependencies.class ) ) {
|
||||||
final Dependencies dependencies = c.getDeclaredAnnotation( Dependencies.class );
|
final Dependencies dependencies = c.getDeclaredAnnotation( Dependencies.class );
|
||||||
for ( final String dependency : dependencies.value( ) ) {
|
for ( final String dependency : dependencies.value( ) ) {
|
||||||
info.addDependency( dependency );
|
info.addDependency( dependency );
|
||||||
|
@ -86,6 +94,7 @@ public final class NewComponentInfo< T >
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find lifecycle methods and dependency injections
|
// Find lifecycle methods and dependency injections
|
||||||
|
NewComponentInfo.findLifecycleActions( info , klass );
|
||||||
NewComponentInfo.findMemberAnnotations( info , klass , klass );
|
NewComponentInfo.findMemberAnnotations( info , klass , klass );
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
@ -118,6 +127,53 @@ public final class NewComponentInfo< T >
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds lifecycle methods in all classes and interfaces a component class extends / implements and adds the
|
||||||
|
* corresponding actions to the information record.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* FIXME: inefficient algorithm
|
||||||
|
*
|
||||||
|
* @param info
|
||||||
|
* the information record
|
||||||
|
* @param klass
|
||||||
|
* the component class
|
||||||
|
* @throws ComponentDefinitionException
|
||||||
|
* if a class or interface in the hierarchy declares more than one method for the same lifecycle stage
|
||||||
|
*/
|
||||||
|
private static < T > void findLifecycleActions( final NewComponentInfo< T > info , final Class< T > klass )
|
||||||
|
throws ComponentDefinitionException
|
||||||
|
{
|
||||||
|
final ArrayList< Method > output = new ArrayList< >( );
|
||||||
|
NewComponentInfo.LC_METHOD_FINDER.find( output , klass );
|
||||||
|
|
||||||
|
final EnumMap< LifecycleStage , Method > methods = new EnumMap< >( LifecycleStage.class );
|
||||||
|
final HashMap< Class< ? > , EnumSet< LifecycleStage > > checks = new HashMap< >( );
|
||||||
|
final int nFound = output.size( );
|
||||||
|
for ( int i = nFound - 1 ; i >= 0 ; i-- ) {
|
||||||
|
final Method m = output.get( i );
|
||||||
|
final Class< ? > mc = m.getDeclaringClass( );
|
||||||
|
EnumSet< LifecycleStage > present = checks.get( mc );
|
||||||
|
if ( present == null ) {
|
||||||
|
present = EnumSet.noneOf( LifecycleStage.class );
|
||||||
|
checks.put( mc , present );
|
||||||
|
}
|
||||||
|
|
||||||
|
final LifecycleStage lma = m.getDeclaredAnnotation( LifecycleMethod.class ).value( );
|
||||||
|
if ( !present.add( lma ) ) {
|
||||||
|
throw new ComponentDefinitionException( "in class " + mc + ": duplicate lifecycle method for " + lma );
|
||||||
|
}
|
||||||
|
methods.put( lma , m );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( final EnumMap.Entry< LifecycleStage , Method > entry : methods.entrySet( ) ) {
|
||||||
|
final Method m = entry.getValue( );
|
||||||
|
m.setAccessible( true );
|
||||||
|
info.setLifecycleAction( entry.getKey( ) , o -> m.invoke( o ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds annotations from the members of a component's class and of its ancestors
|
* Finds annotations from the members of a component's class and of its ancestors
|
||||||
*
|
*
|
||||||
|
@ -139,58 +195,10 @@ public final class NewComponentInfo< T >
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NewComponentInfo.findMemberAnnotations( info , klass , current.getSuperclass( ) );
|
NewComponentInfo.findMemberAnnotations( info , klass , current.getSuperclass( ) );
|
||||||
NewComponentInfo.addLifecycleActions( info , current );
|
|
||||||
NewComponentInfo.addDependencyInjectors( info , current );
|
NewComponentInfo.addDependencyInjectors( info , current );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds component lifecycle actions to an information record by looking for annotated methods
|
|
||||||
*
|
|
||||||
* @param info
|
|
||||||
* the information record to be updated
|
|
||||||
* @param current
|
|
||||||
* the class being examined
|
|
||||||
*/
|
|
||||||
private static < T > void addLifecycleActions( final NewComponentInfo< T > info , final Class< ? super T > current )
|
|
||||||
{
|
|
||||||
final boolean found[] = {
|
|
||||||
false , false , false , false
|
|
||||||
};
|
|
||||||
for ( final Method method : current.getDeclaredMethods( ) ) {
|
|
||||||
final LifecycleMethod lcm = method.getAnnotation( LifecycleMethod.class );
|
|
||||||
if ( lcm == null ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for duplicates
|
|
||||||
final int order = lcm.value( ).ordinal( );
|
|
||||||
if ( found[ order ] ) {
|
|
||||||
throw new ComponentDefinitionException(
|
|
||||||
"in class " + current + ": duplicate lifecycle action for stage " + lcm.value( ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check method
|
|
||||||
if ( method.getParameterCount( ) != 0 ) {
|
|
||||||
throw new ComponentDefinitionException( "in class " + current + ": lifecycle action method for stage "
|
|
||||||
+ lcm.value( ) + " has arguments" );
|
|
||||||
}
|
|
||||||
if ( ( method.getModifiers( ) & Modifier.STATIC ) != 0 ) {
|
|
||||||
throw new ComponentDefinitionException(
|
|
||||||
"in class " + current + ": lifecycle action method for stage " + lcm.value( ) + " is static" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add it
|
|
||||||
found[ order ] = true;
|
|
||||||
info.setLifecycleAction( lcm.value( ) , o -> {
|
|
||||||
method.setAccessible( true );
|
|
||||||
method.invoke( o );
|
|
||||||
method.setAccessible( false );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds fields that require dependency injection in a component's class and adds them to the information record
|
* Finds fields that require dependency injection in a component's class and adds them to the information record
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue