2012-05-24
WicketのAjaxでJavaScriptを動かす
Wicketで、Ajaxで何か処理した後にクライアント(ブラウザ)側でJavaScriptを実行するには
AjaxRequestTarget#appendJavaScript(CharSequence)を使います。
便利。
ちなみにAjaxRequestTargetにはfocusComponent(Component)というメソッドがあって、Ajax処理が完了した後にフォーカスを当てる場所を指定することができます。
便利。
2012-04-02
WicketのHTMLテンプレートはまりどころ
このことの恩恵は非常に大きくて、HTMLでローカルで確認したレイアウトをそのままアプリで使えるわけです。
もちろん他にもHTMLをテンプレートに使えるフレームワークはありますが、Wicketのおもしろいところはパネルによる部品化や継承によるデザインと機能の共通化が可能で、それでいてローカルでHTMLを見てもデザインが壊れない工夫がされている、というところだと思います。
さて便利なWicketのHTMLテンプレート機能ですが、はまりどころがあります。
継承や部品化によって消える部分に、Wicketが動的に処理するタグを含めてはならない、ということです。
例えば
<wicket:remove> <div wicket:id="somePanel"> </div> </wicket:remove>
のようにしてはならん、ということですね。
消える部分にWicketが処理する部分があると、Wicketはテンプレートをどう処理したらいいか分からなくなるので、当然と言えば当然なんですが、wicket:idを付けなくてもWicketが処理を加えるタグの場合、このミスに気付きにくいです。
例えば<a>タグのhref属性や<form>のaction属性がそうです。
たとえタグにwicket:idを付けていなくても、これらの属性に.htmlで終わるファイルを記述していると、WicketはそのHTMLを検索して表示しようとします。
だからここが<wicket:remove>で削除される対象になっていると、Wicketは「ほんとに消しちゃっていいの?何か表示するつもりなんだよね?」と言ってエラーにしてくれるわけです。
Wicketを通さなくても画面レイアウトや遷移を確かめられるようにHTMLを作っていると、特にこれにはまると思います。というかはまりました。かなりの長時間。
Wicketを使うときは気を付けて下さい。
2012-04-01
JavaEEでConnectionを使うときはclose()を忘れずに
最近Glassfish v3.0.1 を使ったJavaEE+Wicketで開発しているのですがはまった出来事があります。
それはjava.sql.Connectionのクローズもれです。
Java1年生かと見紛うばかりの初歩的なミスですが、なぜか「JavaEEのConnectionはclose()しなくてもOK」という思い込みがあったんですよね。
それどころかclose()してしまうとトランザクションが終了してしまうので、close()してはいけないとさえ思っていました。
JTAを使うと、Connectionのクローズのタイミングとトランザクションが終わるタイミングとは切り離されるとのこと。
自分の知識は生兵法なんだなぁ、と反省しきりです。
2012-02-11
WicketのComponentにオブジェクトをインジェクトする
それからJavaEE6の新仕様であるCDIも大好きです。
だったらWicketの中でCDIを使いたくなるのは、ごく自然な流れ。
一応WicketとCDIを統合するライブラリもあるにはあるようですが、まともに動いたことがないんですよね。。。
そんなわけで今回はこれを自作してみました。
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って、本当におもしろい。
2012-02-09
eclipseのWTPでテストクラスをデプロイ対象から外す
eclipseのWTPを使ってWebアプリを開発するときの話題。
開発環境とは言えWEB-INF/libの下には必要最低限のjarしか置きたくありませんが、JUnitのテストクラスを置いているプロジェクトの場合、JUnitのJARを置いておかないとデプロイに失敗してしまいます。
でもやっぱり余計なJARは置きたくない。
というわけでデプロイ対象からテストクラスを外す設定です。
テストクラス専用のソースフォルダと出力先フォルダを作る
こんな感じの設定にします。
テストクラスは、テストクラス専用のソースフォルダに格納するようにします。
Deployment Assemblyからテストクラス用のフォースフォルダを外す
以上でOK!


