WicketのComponentにオブジェクトをインジェクトする

私はWicketというフレームワークが大好きです。
それからJavaEE6の新仕様であるCDIも大好きです。

だったらWicketの中でCDIを使いたくなるのは、ごく自然な流れ。

一応WicketCDIを統合するライブラリもあるにはあるようですが、まともに動いたことがないんですよね。。。
そんなわけで今回はこれを自作してみました。

public class MyApplication extends WebApplication {

    @Override
    public Class<? extends Page> getHomePage() {
        return HomePage.class;
    }

    @Override
    protected void init() {
        try {
            final BeanManager beanManager = InitialContext.doLookup("java:comp/BeanManager");
            getComponentInstantiationListeners().add(new IComponentInstantiationListener() {
                @Override
                public void onInstantiation(final Component pComponent) {
                    inject(beanManager, pComponent);
                }
            });
        } catch (final NamingException e) {
            throw new IllegalStateException(e);
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected void inject(final BeanManager pBeanManager, final Component pComponent) {
        final Class pType = pComponent.getClass();
        final Bean<Object> bean = (Bean<Object>) pBeanManager.resolve(pBeanManager.getBeans(pType));
        final CreationalContext<Object> cc = pBeanManager.createCreationalContext(bean);
        final AnnotatedType<Object> at = pBeanManager.createAnnotatedType(pType);
        final InjectionTarget<Object> it = pBeanManager.createInjectionTarget(at);
        it.inject(pComponent, cc);
    }
}

やってることは単純で、IComponentInstantiationListenerを使ってComponentがインスタンス化されるタイミングをフックして、そこでBeanManagerで明示的にインジェクトしてあげているだけです。

改善点はもちろんあります。JNDIが使えない環境では動かない、とか全てのComponentじゃなくてWebPageにだけDIすれば充分なんじゃない?とか。
でもアイデアの核は上記コードに凝縮されています。

CDIに勝ってる?

実はこの方法、本家CDIより機能的に上回っている部分があります。それはnewで生成したComponentにもDI可能なこと。

これはWicketのIComponentInstantiationListenerのおかげです。WicketのIComponentListenerListenerはCompnentクラスのコンストラクタの中から呼び出されるので、こんなことが可能になります。
以下がその部分のコードです。

    public Component(final String id, final IModel<?> model)
    {
        setId(id);
        getApplication().getComponentInstantiationListeners().onInstantiation(this);
        ...(以下省略)
    }

初めてこのコードを見たときは「なるほど!」と膝を打ってしまいました。
Wicketって、本当におもしろい。