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]

Reply via email to