連載 /JavaServer pages—@ 図 12 マークか付く txt : dl のタクハンドラのソ ース (DefinitionList. java) package text ; import javax. servlet . jsp ・ tagext . * ; import javax. servlet ・ jsp. * ; import java. i0 . lOException; public int doStartTag( ) throws 疇 , ー return lmage ; public String getlmage ( ) { lmage public void setImage(String v) { private String image Ⅱ u11 ; BodyTagSupport public class DefinitionList extends 疇 - JspException { try { 1. getMark() メソッドが追加されている ハンドラのソース ( 図 2 ) とくらべると、 return EVAL_PAGE ; } catch ( 工 OException e) { } pageContext . getOut ( ) . write(" く p>") ; try { public int d0EndTag ( ) throws JspException return EVAL_BODY_INCLUDE ; } catch (IOException e) { } pageContext . getOut() . write(" く p>") ; 84 次に、 try 節のなかで、 String mark rnark 変数を空文字列で衫化しています。 getMark() メソッドの一番う頁の行では、 String 型の 情報を取得しています。 Parent() を利用してはかのタグハンドラからイメージの ます、 getMark() をみてみましよう。ここでは、 get- getMark() の里 の 2 点か変更されています。 2. doEndTag() がマークを出力するようになっている DefinitionList parent を実行しています。 (DefinitionList) 、 getparent ( ) ; getParent() メソッドはすぐ外側のカスタムタグを返 すので、 JSP ファイルのネスティングが正しく言当主され ていて、 txt:dt タグのすぐ外側に txt:dl タグがあれは、 parent 変数には txt:dl タグに対応した DefinitionList のオプジェクトか薇疋されます。 ネスティングの記述が誤っていて、 getParent() が DefinitionList 以外のクラスのオプジェクトを返したと きは、 (DefinitionList)getParent() でキャストに失敗したことを示す CIassCastExcep- tion 例外が盟ーします。このときは、 catch (CIassCastException e) { } の catch 節に制御が移り、 mark 変数は匆月状態の空文字 列が設定されたままになります。 getParent() は txt:dt の外側にカスタムタグがないと null を返しますが、この場合には ClassCastException 例外は発生しません。その代わり、次の行の、 parent . getlmage ( ) で NullPointerException 例外か発生し、 catch (Nu11PointerException e) { } の catch 節に制御が移ります。このときも、 mark 変数 には空文字列か設定されたままになります。 parent 変数に DefinitionList オプジェクトが成疋さ れたときは、 mark = parent . getlmage ( ) ; によって txt:dl タグから取得した image 属性の値が mark 変数に設定されます。ただし、 txt:dl タグで im- age 属匪カ甘旨定されなかったときは null か轂定されてい るので、 mark 変数には空文字列を設定します。 txt:dl タグで image 属匪か指定されたときは、 mark によって HTML の img タグに書き換えられ、それが getMark() メソッドカす値になります。 UNIX MAGAZINE 2003.1
連載 /JavaServer Pages—@ は getClass() メソッドを使います。 getClass() はすべてのクラスの、、大親分 " である Ob- ject クラスで定義されているメソッドで、そのオプジェ クトがどのクラスかを表す Class クラスのオプジェクト を返します。 、、クラスと Class 、オプジェクトと Object か混然とし ていて何がなんだか分からない " という方がいるかもしれ ません。そこで、もっと手つ取り早くツ伶技 " てツ早し 0の . getC1ass ( ) . getName() ていただきましよう。 UNIX MAGAZINE 2003.1 parent . getC1ass ( ) スでは、 parent に null か薇正されるため、 2 番目の、 txt:dt タグの外側にカスタムタグがないケー Tag() メソッドの最後の行に制御が移ります。 は false を返すので、 if 文の中身は実イ子されす、 doStart- name. equals("text . DefinitionList") List " 以外の文字列か設定されます。したがって、 1 番目のケースでは、 name 変数に、、 text. Definition- 2. txt:dt タグの外側にカスタムタグがない。 1. txt:dt タグの外側に txt : dl 以汐 P ) カスタムタグがある。 きの動作は 2 通りに分かれます。 外側のタグハンドラが text. DefinitionList ではないと であれは EVAL-BODY-BUFFERED を返します。 ンドラの名則が成疋され、それが、、 text. DefinitionList" String 型の name 変数には、 parent の値であるタグハ return EVAL_BODY_BUFFERED ; if (name . equals ("text . DefinitionList") ) { String name = parent . getC1ass ( ) . getName ( ) ; いでしようか。 こまで分か川ま、次のコードの処理も分かるのではな java ・ lang. Number" カ亟されます。 lang. Nurnber クラスのオプジェクトの場合でも、文字列 返されます。また、タグとはまったく関係のない java ・ プジェクトであれば、文字列、、 text. DefinitionList" が たとえば、 0 りが図 1 の DefinitionList クラスのオ 始まる完全なクラス名を取得する呼出し方法です。 は、任意のオプジェクト。りについて、パッケージ名で を実行したときに NullPointerException 例外が発生し、 制御が、 catch (NuIIPointerException e) { } に移ります。 catch 節では特別な処理はしていないので、 そのまま doStartTag() メソッドの最後の行に制彳卸が移 ります。 けっきよく、どちらのケースでも、 return SKIP_BODY ; が実行されます。その結果、 JSP 工ンジンは txt:dt タグ の本体部分の処理をスキップします。 txt:dt の終了タグに対する里 DefinitionTerm クラスの doEndTag() メソッドのお もな仕事は、 JSP 工ンジンがタグハンドラのオプジェクト にこっそり保存しておいたタグの本体部分を取り出して、 プラウザに送ることです。 doEndTag() メソッドの処理 をみていきましよう。 ます、 String 型の bodystr 変数が空文字列 ( ' ' ' ' ) で初 期化されます。 String bodystr try { bodystr = getB0dyContent() . getString() + " く br>" } catch (NuIIP0interException e) { } でタグの本体部分を文字列として取り出し、 bodystr 変数 にセットします。このとき、リストとして表示させるため に、本体部分の後ろに改行を指示する <br 〉タグを付けて います。 このように、 txt:dl タグと txt:dt タグのネスティング が正しいときは bodystr 変数に txt:dt の本体の文字列が 設疋されるわけですが、正しくネスティングされていない ときはどうなるのでしようか。 doStartTag() メソッドで SKIP-BODY を返した場合について考えてみましよう。 JSP 工ンジンは SKIP-BODY が返されると本体部分 の処理をおこなわないので、タグの本体部分は保存されま せん。そのため、 getBodyContent() メソッドは null を getBodyContent ( ) . getString() 返します。すると、 79
連載 JavaServer pages 図 13 マークが付く txt:dt のタクハンドラのソース (DefinitionTerm. Java) package text ; import javax. servlet . jsp. tagext . * ; import javax . servlet . jsp. * ; import java. iO. IOException; bodystr = getMark ( ) + getB0dyContent ( ) . getString() + " く br>" ・ try { String bodystr public int d0EndTag ( ) throws JspException { " " 十 mark 十 " \ " > ー (DefinitionList)getParent ( ) ; r e turn mark ; catch (NuIIPointerException e) { } } catch (C1assCastException e) { } mark ーく img } else { mark = " " ・ ー null) { i f (mark mark = parent ・ getlmage ( ) ; DefinitionList parent try { String mark private String getMark() { return SKIP_BODY ; } catch (NuIIP0interException e) { } て eturn EVAL_B ODY_BUFFERED ; if (name . equals("text. DefinitionList") ) { String name = parent . getC1ass ( ) . getName ( ) ; try { Tag parent = getParent ( ) ; public int doStartTag ( ) throws JspException { public class DefinitionTerm extends B0dyTagSupport { } catch (Nu11PointerException e) { } try { pageContext . getOut() . write(bodystr) ; } catch (IOException e) { } return EVAL_PAGE ; doEndTag() の里 UNIX MAGAZINE 2003.1 です。マークカ咐く txt:dt の場合には、 getMark() メ で、 getMark() メソッドを呼び出しているかどうかだけ getString() + " く br>" ・ bodystr = getMark ( ) + getB0dyContent ( ) . EndTag() メソッドの違いは、 クが付く txt:dt とマークが付かない txt:dt タグの do- 次に、 doEndTag() メソッドをみてみましよう。マー ソッドからイメージを表小する img タグの言当を受け取 り、リストの文字列の頁に追カ日しています。 マーク付きのリストの表示 image 属性を追加した txt:dl タグを使うには、 TLD ファイル内の txt:dl タグの言当を変える必要があります。 text. tld に追加した dl タグを次のように書き換えてくだ さい。 85
連載 /OavaServer Pages—@ 図 1 txt:dl のタクハンドラのソース (DefinitionList. return EVAL_BODY_INCLUDE ; } catch (IOException e) { } pageContext. getOut ( ) . write(" く p>") ; try { JspException { public int d0StartTag ( ) throws - BodyTagSupport public class DefinitionList extends - import java. iO. 工 OException; import javax. servlet ・ jsp ・ * ; import javax. servlet . jsp. tagext . * ; package text ; Java) pageContext. getOut() . write(" く P>") ; try { public int d0EndTag ( ) throws JspException } catch (IOException e) { } return EVAL—PAGE ; ( 誌面の都合長て折リ返しています。以 - ト 1 司様 ) の 2 不鶤頁のメソッドを定義しています。 も、 これらはいすれ 1. 段落の区切りを意味するく p 〉を表示する 2. JSP 工ンジンに戻り値でタグの処理カ 1 去を孑帛パする という処理を順番におこなっています。 doStartTag() は、 EVAL-BODY-INCLUDE を返 しています。これにより txt:dl タグの本体部分の処理は JSP 工ンジンに委ねられ、 DefinitionList 側では特別な 処理を必要としません。 一方の doEndTag() メソッドは、 EVAL-PAGE を返 すことで、 JSP 工ンジンに txt:dl の終了タグ以降も処理 を続けるように孑嗣しています。 txt : dt タグのタグハンドラ 次は txt : dt のタグハンドラです。このタグハンドラで は、次のような処理をおこなうことにします。 1. txt:dt タグの外側のタグを取得する。 2. 外側のタグが txt : dl タグかどうかを調べる。 UNIX MAGAZINE 2003.1 3. txt:dl タグならタグ本体を表示して改行・し、さもなくは 何も表示しない。 図 2 に、 txt:dt のタグハンドラのソース、、 Definition- Term. java" を示します。ネスティングの状態の判断は doStartTag() メソッドでおこない、 doEndTag() メソッ ドでは ( もしあれは ) 保存されているタグ本体をプラウサ ・ findAncestorWithClass() ・ getParent() 2 不鶤頁のメソッドが用意されています。 タグのネスティングの状態を調べる手段としては、次の 外側のタグを得る getParent ( ) 上に出力します。 注意 1 : getparent() はカスタムタグしかみつけられ おきましよう。 getparent() を使用する際の注意点を 3 つほど挙げて getparent ( ) を使用する際の注意点 parent 変数に設疋されます。 という行では、すぐ外側のタグに対応するタグハンドラが Tag parent = getParent ( ) ; したがって、図 2 の doStartTag() の最初にある、 ジェクトです。 (txt:dl 〉タグに対応する DefinitionList クラスのオプ します。このとき getparent() が返すのは、下線部の に対して、矩形で囲んだ <txt:dt 〉タグを角斤していると く /txt :dl> 区土医宣 : 垣 ] ー朝一タく / txt :dt> く txt :dl> たとえは、次のような JSP ページの内容、 クトを返します。 スタムタグの解木寺に生成されたタグハンドラのオフジェ を返すメソッドです。もっと厳密にいえは、すぐ外側のカ います。 getparent() は、角〒中のタグのすぐ外側のタグ doStartTag() では getparent() メソッドを使って たとえは、 77
連載 /JavaServer Pages—・の 図 15 image 属性をもつ txt:dt のタクハンドラのソース (DefinitionTerm. java package text ; import javax . servlet . jsp. tagext . * ; import Javax . servlet . JSP. * ; import java. i0 . lOException; public class DefinitionTerm extends B0dyTagSupport { String image = Ⅱ u11 ; public int d0StartTag ( ) throws JspException { public void setImage(String v) { lmage = V ; private String getMark() { if (image ! = Ⅱ u11 ) { return " く img src=\ String mark = " " ・ try { DefinitionList parent mark = parent . getlmage ( ) ; if (mark null) { mark } else { " く img 十 mark 十 " \ " > " mark } catch (CIassCastException e) { } catch (NuIIPointerException e) { } return mark ; " " 十 1mage 十 " \ " > ー (DefinitionList)getParent ( ) ; public int d0EndTag ( ) throws JspException { 図 16 マークが付く txt:dt タグを使った表示 今回は、複数のカスタムタグを組み合わせるガ去を紹介 しました。すぐ殞則のタグを取得する getParent() メソッ - 万イル ( E ) 編集表示 ( ) ジャンプブックマーり ( 印ツーウインめへルプ ( 印 ドを利用して、カスタムタグのネスティングの状態を調べ ~ / 目に [ 」物ⅱホームラジオ常コプマゆいー” e 、新着、お勧助、メン ました。また、複数のカスタムタグのあいたで情報を受け ロ 当、「一」が蛔登場すまことわざ txt 引にイメーシのマークを設定 渡す方法も紹介しました。 ◆一朝一タ 外側のカスタムタグ (txt:dl) がもっている情報を内側 一喜一憂 のカスタムタグ (txt:dt) が得る例しか紹介しませんでし 学一長一短 ◆一一其目一一会」 たが、情報の取得に使ったメソッドを情報を設定するメ 第 9 ・ロ宀メ発了 ( 。た物 ソッドに書き換えれは、内側のカスタムタグの情報を外側 のカスタムタグべ度すこともできます。興床のある方は試 情報を複数のカスタムタグのあいだで受け渡すことか可阨 、、ムヒ してみてください。 です。 ( あらい・みちこ ASTEC) 「一」な 2 回登鶸ることき一 N 引 30 を 言同ロ ☆ 87 UNIX MAGAZINE 2003.1
JavaServer Pages 荒井美千子 タグのネスティング 前回までに紹介したカスタムタグは、単体て利用するも のだけでした。ところで、 HTML のタグには、 ・ table タグと tr 、 td タグ ・ⅲタグとⅱタグ ネスティングしたカスタムタグ タグの本体て指定した文字列を 1 行に 1 っすっ表示しま グは HTML の dl タグと dt タグを真似たもので、 txt:dt 名前から想像できるかもしれませんが、このカスタムタ を作ってみましよう。 ・ txt:dt ・ txt:dl て、リストを表示するカスタムタ久 最初に、カスタムタグのネスティングの簡単な例とし タグをとりあげます。 このようなネスティングした ( 入れ子になった ) カスタム 合わせて特定の機能を実現することができます。今回は、 これらと同しく、 JSP でも複数のカスタムタグを組み わせて使うものがあります。 のように、あるタグの本体部分に別のタグを入組み合 76 く /txt:dl> く txt :dt>—期ー会く /txt : dt> く txt :dt>—長一短く /txt : dt> く txt :dt>—喜一憂く /txt : dt> く txt :dt>—朝一タく /txt :dt> く txt : d1> たとえは、 す。 は、プラウザ - E では次のように表示されます。 ー長一短 このようなカスタムタグの実現に必要な、 ・タグハンドラ ( カスタムタグの処理を実装した Java の txt : dl タグのタクハンドラ 番に紹介していきます。 および、このタグハンドラを使った JSP ページの例を順 ・ web. xml ファイル ・ TLD ( タグライプラリ記述子 ) ファイル コード ) UNIX MAGAZINE 2003.1 ・終了タグの角財芋に呼び出される doEndTag() ・開始タグの角財芋に呼び出される doStartTag() DefinitionList クラスでは、 java" を示します。 txt:dl のタグハンドラのソース、、 DefinitionList. 最初に txt : dl のタグハンドラをみていきましよう。図 表示し、正しくなければ何も表示しないというものです。 ティングが正しい状態なら txt:dt タグの本体の文字列を グが txt:dl タグの内側に記述されているかを調べ、ネス 今回紹介するカスタムタグのタグハンドラは、 txt:dt タ るようにすることです。 ペ必要に応じて外側のタグから内側のタグへ情報を渡せ ントは、タグのネスティンクの状態が正しいかどうかを調 ネスティングしたカスタムタグを作るときのキーポイ
連載 /JavaServer Pages—@ 図 2 txt:dt のタクハンドラのソース (DefinitionTerm. java) package text ; import Javax . servlet . jsp ・ tagext . * ; import javax . servlet ・ jsp ・ * ; import java. i0. IOException; public class DefinitionTerm extends BodyTagSupport { public int doStartTag() throws JspException { Tag parent = getParent ( ) ; try { String name = parent . getC1ass() . getName() ; if (name . equals("text . DefinitionList")) { return EVAL_BODY_BUFFERED ; } catch (Nu11PointerException e) { } return SKIP_BODY ; public int doEndTag ( ) throws JspException { String bodystr try { bodystr = getBodyContent() . getString() + " く br>" } catch (Nu11PointerException e) { } try { pageContext . getOut ( ) . write(bodystr) ; } catch (IOException e) { } return EVAL_PAGE ; く txt :dl> く b > : 迫司ー朝一タく / txt :dt> く /b> く /txt :dl> のように、 txt:dt タグが HTML の b タグで囲まれてい たとしても、すぐ外側の b タグではなく下線部のく txt:dl 〉 タグがみつかります。 注意 2 : ほかの API で作ったカスタムタグは基本的に getParent ( ) では取得できない カスタムタグを作るガ去は 1 つだけではありません。 の連載では、 javax. servlet. jsp. tagext ノ、ツケージに含ま れるインターフェイスやクラスを利用したカスタムタグの 作り方を紹介してきましたが、別の API セット 1 を使っ てカスタムタグを作成することも可能です。ただし、ほか の API で作ったカスタムタグは基本的に getParent() で 1 2 ( ) 02 年 8 ~ 9 月号で紹介した JSTL (JSP Standard Tag Li- brary) 用の API など。 78 は取得できません。 ラも意 3 : 解析中のタグの外側にカスタムタグがない場合、 getParent() メソッドは null を返す たとえは、 く body> 亟亟 : 亟司ー朝一タく / txt : dt> く /body> のように txt:dt タグの外側にカスタムタグが 1 つもな いときは、 getParent() の返す値は null になります。返 されたオプジェクトのメソッドを呼び出したり、プロバ ティにアクセスするコードを記主するときは注意してくだ タグハンドラのクラス名を調べることができます。 タグハンドラのオプジェクトか取得できたら、そこから タグハンドラのクラス名を調べる さい。 これに UNIX MAGAZINE 2003.1
連載 /JavaServer pages ーの 図 3 txt:dl 、 txt:dt タクを使うための TLD ファイルの記述 (text. tld) く ?xml version="l . 0 " enc0ding="ISO—8859—I" ? > く ! DOCTYPE taglib —//Sun Microsystems , lnc. //DTD JSP Tag Library 1.2//EN" PUBLIC " "http: //java. sun. com/dtd/web-jsptag1ibrary—1-2.dtd"> く taglib> く tlib—version>l . 0 く /tlib—version> く jsp—version>l . 2 く /jsp-version> く short—name>txt く /short—name> く uri>http://www. astec. CO. jp/text く /uri> く disp1ay—name>Text Sty1e く /display—name> く description>Text StyIe Library く /description> く tag> く name>dl く /name> く tag—class>text . DefinitionList く /tag—class> く /tag> く tag> く name>dt く /name> く tag—class>text . DefinitionTerm く /tag—class> く /tag> く /taglib> 図 4 txt:dl 、 txt:dt タグを使うための web. xml ファイルの記述 く ?xml version="l . 0 " enc0ding="ISO—8859—1"?> く ! DOCTYPE web—app PUBLIC "—//Sun Microsystems, lnc . //DTD Web App1ication 2.3 / / EN " "http: //java. sun. com/dtd/web-app-2-3.dtd"> く web—app> く taglib> く taglib—uri>http: / / . astec . co . jp/text く /taglib—uri> く tag1ib-10cation>/WEB-INF/t1d/text. tld く /taglib-location> く /taglib> く /web-app> を実行しているときに NullPointerException 例外が発 生し、制御が、 catch (NuIIPointerException e) { } に移ります。したがって、 bodystr 変数は初期化のとき に設定した空文字列か残ったままの状態になります。 ネスティングが正しくても正しくなくても、 doEnd- Tag() メソッドの後半の、 pageContext . getOut() . write (bodystr) ; で、 bodystr 変数に設定された文字列をプラウサに表示し 80 ます。 TLD ファイルと web. xml カスタムタグを利用するには、 JSP 工ンジンにカスタ ムタグの使い方を知らせるための言当を TLD ファイルと web. xml ファイルに追加する必要があります。 txt:dl タ グと txt:dt タグ用の TLD ファイル、、 text. tld" を図 3 に、 web. xml ファイルを図 4 に示します。 これらのファイルを、それぞれ JSP のアプリケーショ ンをインストールしたディレクトリの下の、 WEB—INF/t1d/text . tld UNIX MAGAZINE 2003.1
連載 /JavaServer Pages ーの 図 14 マーク付きのリストの表示結果 2. doEndTag() 物方イル編集 ( 印表示 ( ) ジャンプ 0 ブ沖マーク⑧ツールウインドウ ( 盟ヘルプ ( 印 朝 の 2 つは「マークカ咐く txt:dt タグ」の項で紹介した図 、凵新を物ⅱホームラジオ検常新プめマーク、いは 1 を Me ”色、新著籌おを助、メンバ 13 のメソッドと同しなので内容は省略しました。 、」、「一」が 2 回場することわど 変史したのは、 txt 引にイメージのマークを設定 1. image 属性の値を保存しておく image 変数を追加 ー長一短 2. image 属性の角行時に呼び出される setlmage() メソ ッドを定義 0 ロ QY ・ロメ : + 了“ 23 ゆ 3. マークの内容を取得する getMark() メソッドを変史 く tag> く name>dl く /name> という点ですが、これらも以前の実装の系区しで目新しい く tag—class>text . DefinitionList く /tag— class> ことはしていないので、コードの説明は省略します。 く attribute> く name>image く /name> image 属 1 生を追加した txt:dt タグを使うには、 txt:dl く /attribute> タグの場合と同様に、 TLD ファイル内の txt:dt タグの く /tag> 当を変える必要があります。 text. tld の dt タグを次の 図 14 は、マークカ咐くカスタムタグを使った JSP ファ ように書き換えてください。 イルの表万列です。使用した JSP ファイルのタグの記述 は次のとおりです。 く tag> く name>dt く /name> txt : dl にイメージのマークを設定 : く tag—class>text . DefinitionTerm く /tag—class> く txt :d1 image="suits . gif"> く attribute> く txt:dt>—朝一タく /txt:dt> く name>image く /name> く txt :dt>—喜一憂く /txt : dt> く /attribute> く txt :dt>—長一短く /txt :dt> く /tag> く txt : dt>—期ー会く /txt :dt> く /txt :dl> この新しい txt:dt タグを使って、 image 属性に指定している、、 suits. gif" は、図 14 のリ txt : dl にイメージのマークを設定 : ストの先頭に表示されているトランフ。の 4 種類のマーク く txt :d1 image="suits. gif"> く txt :dt image="spade ・ gif">—朝一タく /txt :dt> です。 く txt :dt>—喜一憂く /txt :dt> txt:dl で image 属性を指定しなければ、 さきはどの図 く txt :dt image="heart . gif't>—長一短く /txt :dt> 6 と同様にマークが付かないリストが 1 行に 1 っすっ並ん く txt : dt>—期ー会く /txt :dt> く /txt :dl> だ状態になります。 という内容の JSP ファイルを表示させた結果か図 16 で txt : dt でもリストのマークを指定 す。 最後に、 txt:dt にオマケの機能を付けてみましよう。 1 番目と 3 番目のリストのう頁には、 txt:dt タグのⅲト txt:dt タグにも image 属性を追加し、 txt:dt でイメージ age 属羅で指定したスペードのマーク (spade. gif) とハ を指定していれば txt : dl よりも優先されるようにします。 トのマーク (heart. gif) か表示されています。また、 2 番 txt:dl のタグハンドラには変史はありません。「マーク 目と 4 番目の txt:dt タグでは image 属 1 生か指定されてい カ咐く txt:dl タグ」の項て紹介した図 12 の Definition- ないので、 txt:dl タグの image 属性てオ旨定した suits. gif List クラスをそのまま使ってください。 を継承して、トランプの 4 種類のマークが表示されてい txt:dt のタグハンドラは図 15 に示しました。このタグ ます。 ハンドラのメソッドのうち、 こでは、属 1 生で指定された値を 2 つのカスタムタグ のあいだで受け渡しましたが、属・陸にかぎらすさまざまな 1. doStartTag() 「一」が 2 回場することわど一 N 引 ! 同ロ 1 三ロ 86 UNIX MAGAZINE 2003.1