カスタムタグの内容をタグハンドラで処理する
今まではJSPコンテナが直接処理していたカスタムタグの内容を,タグハンドラで取得,処理してみた.
タグの内容の評価を単にJSPコンテナに任せるだけの方法は既に確認した.次は,タグハンドラがタグの内容を取得,評価する方法を探ってみる.
本頁では以下のサンプルJSPで,タグの内容の大文字,小文字の変換を行う.
カスタムタグ
タグの内容をタグハンドラで評価するには,BodyTagインタフェースを実装している必要がある,今回のタグハンドラはBodyTagインタフェースを実装したBodyTagSupportを継承している.
<sample:handle-body>は必須属性upperOrLowerを持つ.値はupper,lowerのいずれかである(大文字,小文字の区別はない).値がupperならタグハンドラによってタグの内容が大文字に変換される.lowerなら逆に小文字に変換される.そのタグハンドラを以下に示す.
サンプルのタグハンドラのdoStartTagメソッドでは
まずdoEndTagによる出力は""で囲っていることに注意.doInitBodyでのwriteでは直接ブラウザへの出力ストリームには流れず,doEndTagで一旦取り出してからwriteすることで,ブラウザまで到達していることが分かる.
また,doStartTagでのoutのOIDとdoInitBodyでのoutのOIDが異なり,doInitBody内でのoutとbodyContentのOIDが一致することにも注意.
さらにdoInitBodyによる"doInitBody : body ="という出力.これからdoInitBodyではbodyContentにタグの内容はまだ格納されていないことが分かる.故にdoInitBody内のif分の処理の結果(bodyIsEmptyの値の操作)はうまくいっていない.
BodyTag.EVAL_BODY_BUFFEREDを返している.これによって,JSPコンテナはタグハンドラがタグの内容を評価することを知り,そのために必要な以下の処理を行う.
- JSPWriter変更
- PageContextインスタンス(タグハンドラ内ではpageContextに格納されている)にbodyContentをpushBodyする.タグハンドラで
pageContext.getOut()
とすると,最後にpushされたJSPWriterが返る.で,bodyContentは出力ストリームを持たないので,writeしてもブラウザに文字列は出力されない.EVAL_BODY_BUFFEREDのBUFFEREDという文字列から察しがつくかもしれないが,bodyContentにwriteすると,出力がバッファリングされ,後にgetStringすることで一気に取り出せる. - setBodyContent呼び出し
- タグハンドラにタグの内容情報であるbodyContentを渡す.
- doInitBody呼び出し
- タグの内容を初期化するのに使用する.BodyTagSupportのそれは何もしない.必要に応じてオーバーライドする.
- (タグの内容の評価)
- JSPWriter変更
- PageContectインスタンス(タグハンドラ内ではpageContextに格納されている)からpopBodyする.
...
pageContext.getOut().write("doInitBody : out = "+ pageContext.getOut() + "<br/>");
pageContext.getOut().write("doInitBody : bodyContent = " + bodyContent + "<br/>");
...
といった処理をしている.先述のように,doInitBodyの段階では,
pageContext.getOut()で返るJSPWriterと
bodyContentに格納されているJSPWriter(※)が同じものである.そしてbodyContentは出力ストリームを持たないので,ブラウザに直接この文字が渡されることはない.次にdoEndTagを見てみる.まず
if (bodyContent == null) {
pageContext.getOut().write( "doEndTag : bodyContent is null.<br/>");
}
JSPにカスタムタグが<.../>ではなく<...></...>と記述された場合,setBodyContent(さらにdoInitBody)が呼ばれないらしい.ということで,nullチェックを行っている.あとは属性の値に応じて処理をする.
else if (upperOrLower == UPPER) {
pageContext.getOut().write( "doEndTag : \""
+ bodyContent.getString().toUpperCase()
+ "\"<br/>");
}
else if (upperOrLower == LOWER) {
pageContext.getOut().write( "doEndTag : \""
+ bodyContent.getString().toLowerCase()
+ "\"<br/>");
}
ここでbodyContentからgetStringしてデータを取り出している.これはタグの内容とdoInitBodyでの
pageContext.getOut().writeによる出力である.このようにdoInitBodyではbodyContentをバッファに見立ててそこにwriteし,doEndTagで取り出して出力というのが最も基本的なパターンである.なお,doEndTag時点では,
pageContext.getOut()で返るJSPWriterと
bodyContentに格納されているJSPWriterは異なる.すなわち前者はブラウザへとつながるストリームを持っている「いつもの」であり,writeすると出力がブラウザにとぶ. JSPからの出力を確認してみる.
※ public abstract class BodyContent extends JspWriter
念のために今回のサンプルのtldファイルを以下に示す.
今までのサンプルと同じtaglibに追加した.最後の要素tagが今回のサンプル用のものである.今回はタグの内容はタグハンドラで操作するので,
<body-content>tagdependent</body-content>とした.さらに属性upperOrLowerを必須属性にしてみた.
<attribute>
<name>upperOrLower</name>
<required>true</required>
</attribute>

