On Mon, Apr 28, 2008 at 6:27 AM, James Carman
<[EMAIL PROTECTED]> wrote:
> Yes, this would involve making up some rules about the order in which
> the parent class' initializer methods are invoked. A couple that come
> to mind:
>
> 1. There should only be one initializer method declared per class (to
> avoid the which do we call first problem).
> 2. Parent class' initializer methods should be invoked first.
>
> I don't agree that marking "lifecycle" methods with annotations is an
> abuse (of annotations?) at all. Perhaps this wouldn't belong in the
> "core", but I can see it as an extension or a wicketstuff project
> maybe?
>
I actually played around with this a bit. I've created an annotation:
@Retention( RetentionPolicy.RUNTIME)
@Target( ElementType.METHOD)
public @interface Initialization
{
}
Then, I created the listener:
public class InitializationInstantiationListener implements
IComponentInstantiationListener
{
//**********************************************************************************************************************
// Fields
//**********************************************************************************************************************
private final Map<Class, Initializer> initializersMap = new
HashMap<Class, Initializer>();
//**********************************************************************************************************************
// IComponentInstantiationListener Implementation
//**********************************************************************************************************************
public void onInstantiation( Component component )
{
Initializer initializer = getInitializer(component);
initializer.initialize(component);
}
private synchronized Initializer getInitializer( Component component )
{
final Class<? extends Component> componentClass = component.getClass();
Initializer initializer = initializersMap.get(componentClass);
if( initializer == null )
{
final List<Method> initializationMethods =
getInitializationMethods(component);
initializer = createInitializer(componentClass,
initializationMethods);
initializersMap.put(componentClass, initializer);
}
return initializer;
}
//**********************************************************************************************************************
// Other Methods
//**********************************************************************************************************************
private synchronized List<Method> getInitializationMethods(
Component component )
{
List<Method> initializationMethods = new LinkedList<Method>();
Class c = component.getClass();
while( c != null )
{
Method initializer = getInitializationMethod(c);
if( initializer != null )
{
initializationMethods.add(0, initializer);
}
c = c.getSuperclass();
}
return initializationMethods;
}
private Method getInitializationMethod( Class c )
{
Set<Method> initializers = new HashSet<Method>();
final Method[] declaredMethods = c.getDeclaredMethods();
for( Method declaredMethod : declaredMethods )
{
if( declaredMethod.getAnnotation(Initialization.class) != null )
{
if( Modifier.isPublic(declaredMethod.getModifiers()) &&
Void.TYPE.equals(declaredMethod.getReturnType()) &&
declaredMethod.getParameterTypes().length == 0 )
{
initializers.add(declaredMethod);
}
else
{
throw new WicketRuntimeException("Invalid
initializer method declared on class " + c.getName() +
". Initializers must be public, have a
void return type, and take no parameters.");
}
}
}
switch( initializers.size() )
{
case 1:
return initializers.iterator().next();
case 0:
return null;
default:
throw new WicketRuntimeException("Class " +
c.getName() + " declares multiple (" + initializers.size() +
") initializer methods.");
}
}
protected Initializer createInitializer( Class componentClass,
List<Method> initializationMethods )
{
return initializationMethods.isEmpty() ? new NullInitializer()
: new ReflectionInitializer(initializationMethods);
}
//**********************************************************************************************************************
// Inner Classes
//**********************************************************************************************************************
protected static interface Initializer
{
public void initialize( Component component );
}
protected static class NullInitializer implements Initializer
{
public void initialize( Component component )
{
// Do nothing!
}
}
protected static class ReflectionInitializer implements Initializer
{
private final List<Method> initializationMethods;
public ReflectionInitializer( List<Method> initializationMethods )
{
this.initializationMethods = initializationMethods;
}
public void initialize( Component component )
{
for( Method initializationMethod : initializationMethods )
{
try
{
initializationMethod.invoke(component);
}
catch( IllegalAccessException e )
{
throw new WicketRuntimeException("Failed to invoke
initializer method " + initializationMethod.getName() +
" on component of type " +
component.getClass().getName() + ".", e);
}
catch( InvocationTargetException e )
{
throw new WicketRuntimeException("Failed to invoke
initializer method " + initializationMethod.getName() +
" on component of type " +
component.getClass().getName() + ".", e);
}
}
}
}
}
If one really wanted to, they could override the createInitializer()
method to provide the capability of dynamically generating a class at
runtime which merely invokes the initialization methods on the
component (using Javassist perhaps). This class basically enforces
the two simple rules I mentioned before.
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]