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.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
|
@ -28,12 +29,19 @@ public final class NewComponentInfo< T >
|
|||
{
|
||||
/** Member finder that looks for the default constructor */
|
||||
private static final MemberFinder< Constructor< ? > > CONSTRUCTOR_FINDER;
|
||||
/** Member finder that looks for lifecycle methods */
|
||||
private static final MemberFinder< Method > LC_METHOD_FINDER;
|
||||
|
||||
|
||||
static {
|
||||
CONSTRUCTOR_FINDER = new MemberFinder< >( ( final Class< ? > c ) -> c.getDeclaredConstructors( ) , false );
|
||||
NewComponentInfo.CONSTRUCTOR_FINDER
|
||||
.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
|
||||
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 );
|
||||
for ( final String dependency : dependencies.value( ) ) {
|
||||
info.addDependency( dependency );
|
||||
|
@ -86,6 +94,7 @@ public final class NewComponentInfo< T >
|
|||
}
|
||||
|
||||
// Find lifecycle methods and dependency injections
|
||||
NewComponentInfo.findLifecycleActions( info , klass );
|
||||
NewComponentInfo.findMemberAnnotations( info , klass , klass );
|
||||
|
||||
return info;
|
||||
|
@ -94,7 +103,7 @@ public final class NewComponentInfo< T >
|
|||
|
||||
/**
|
||||
* Finds the default constructor for the specified class
|
||||
*
|
||||
*
|
||||
* @param klass
|
||||
* the class
|
||||
* @return the default constructor (even if it is private)
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -139,58 +195,10 @@ public final class NewComponentInfo< T >
|
|||
return;
|
||||
}
|
||||
NewComponentInfo.findMemberAnnotations( info , klass , current.getSuperclass( ) );
|
||||
NewComponentInfo.addLifecycleActions( 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
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue