PGBox
P
G
Box

カスタムタグの作成【遅延評価EL式】

JSPのメニューへ戻る



使用した環境
JDK 6 Update 11
Tomcat 6.0.18

遅延評価のEL式を属性で受け取る事により、EL式の対象プロパティに値をセットしたり、タグ内でEL式で指定されたメソッドを起動する事が可能となります。


通常EL式でタグ属性に値をセットする場合
<x:xxx attr="${xxx}" />
といったように記述します。
これは即時評価と呼ばれ、タグクラス属性のセッターに値がセットされる前に式が評価され、結果が
タグの属性に渡されます。

これを
<x:xxx attr="#{xxx}" />
と記述する事により、タグクラス内の任意のタイミングで評価を行う事が可能となります。
これを遅延評価と呼びます。

遅延評価を行う場合、タグクラス側で遅延評価式を受け取る対処が必要となりますが
処理中の任意のタイミングで評価を行う事により、EL式に該当するプロパティのオブジェクトに対し
値のセットなどを行う事が可能となります。


値の遅延評価


値の遅延評価式を利用して、EL式に対し値をセットするタグを作成してみます。
まずtldで値の遅延評価を受け取るのための定義を行います。
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xml="http://www.w3.org/XML/1998/namespace"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
          version="2.1">
    
    <tlib-version>1.0</tlib-version>
    <uri>/sample</uri>
    
    <tag>
        <name>sample</name>
        <tag-class>sample.SampleTag</tag-class>
        <body-content>empty</body-content>

        <attribute>
            <name>exp</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <deferred-value />
        </attribute>
        
    </tag>
    
</taglib>
tldファイルの詳細な情報についてはtldファイルを参照してください。

<deferred-value />要素を記述する事により、値の遅延評価式を受け取る事が可能となります。


値の遅延評価を処理するタグクラスは以下のようになります。
package sample;

import javax.el.ValueExpression;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class SampleTag extends TagSupport {
    
    /** 値の遅延評価式 */
    private ValueExpression exp;
    
    @Override
    public int doStartTag() throws JspException {
        
        // EL式の評価結果が読み取り専用の場合は値のセットを行わない
        if (!exp.isReadOnly(pageContext.getELContext())) {
            
            // EL式を評価し、値をセットする
            exp.setValue(pageContext.getELContext(), "値の遅延評価のサンプル");
        }
        
        return SKIP_BODY;
    }

    public void setExp(ValueExpression exp) {
        this.exp = exp;
    }
    
}

値の遅延評価式を受け取る属性の型はjavax.el.ValueExpressionである必要があります。
ValueExpressionは以下のようなメソッドを持ちます。
メソッド意味
Class getExpectedType()式の評価結果の型の制限値。tldの<deferred-value><type>で定義されている型が取得できる。tldでtype要素を省略している場合はjava.lang.Objectが取得される。
Class getType(ELContext context)EL式を評価し、値の型を取得する。
Object getValue(ELContext context)EL式を評価し、値を取得する。
boolean isReadOnly(ELContext context)EL式の評価結果のプロパティが読み取り専用の場合にtrueが取得される。
void setValue(ELContext context,Object value)EL式を評価し、値をセットする。
String getExpressionString()EL式を取得する。
boolean isLiteralText()EL式がリテラルテキストから作成されたものの場合にtrueが取得される。




サンプル動作の確認ために、以下のような値を保持するだけのクラスを作成します。
プロパティを保持するだけのシンプルなクラスです。
package sample;

public class SampleItem {
        
    private String aaa;
    
    public String getAaa() {
        return aaa;
    }
    public void setAaa(String aaa) {
        this.aaa = aaa;
    }
}


このタグを使用するにはJSPで以下のように記述します。
<%@ page contentType="text/html; charset=Windows-31J" pageEncoding="Windows-31J" %>
<%@ page import="sample.SampleItem" %>
<%@ taglib uri="/sample" prefix="s" %>

<%
pageContext.setAttribute("item", new SampleItem());
%>

<s:sample exp="#{item.aaa}" />

${item.aaa}



結果は以下のようになります。
値の遅延評価のサンプル


SampleItemのプロパティ「aaa」を遅延評価式#{item.aaa}でタグクラスに渡し、
タグ内で遅延評価を行う事で、値のセットを行っています。



メソッドの遅延評価


メソッドの遅延評価式を利用して、EL式で渡されたメソッドを呼び出して、結果を出力するタグを作成してみます。

まずtldで値の遅延評価を受け取るのための定義を行います。
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xml="http://www.w3.org/XML/1998/namespace"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
          version="2.1">
    
    <tlib-version>1.0</tlib-version>
    <uri>/sample</uri>
    
    <tag>
        <name>sample</name>
        <tag-class>sample.SampleTag</tag-class>
        <body-content>empty</body-content>

        <attribute>
            <name>exp</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <deferred-method>
                <method-signature>
                    ()
                </method-signature>
            </deferred-method>

        </attribute>
        
    </tag>
    
</taglib>
tldファイルの詳細な情報についてはtldファイルを参照してください。

<deferred-method>要素を記述する事により、メソッドの遅延評価式を受け取る事が可能となります。

<method-signature>要素には、メソッドのシグネチャを記述します。
今回のサンプルでは「戻り値の指定なし」「引数なし」としておくので
<method-signature>
    ()
</method-signature>
といった記述になります。

戻り値を指定したり、引数を受け取るメソッドの場合は
<method-signature>
    java.lang.String (java.lang.String, int)
</method-signature>
といったようにシグネチャを記述する必要があります。



メソッドの遅延評価を処理するタグクラスは以下のようになります。
package sample;

import java.io.IOException;

import javax.el.MethodExpression;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class SampleTag extends TagSupport {
    
    /** メソッドの遅延評価式 */
    private MethodExpression exp;
    
    @Override
    public int doStartTag() throws JspException {

        // 遅延EL式のメソッドを呼び出す
        Object result = exp.invoke(pageContext.getELContext(), null);
        
        // メソッドの実行結果を出力する
        try {
            pageContext.getOut().print(result);
        } catch (IOException e) {
            throw new JspException(e);
        }
        
        return SKIP_BODY;
    }

    public void setExp(MethodExpression exp) {
        this.exp = exp;
    }
}


値の遅延評価式を受け取る属性の型はjavax.el.MethodExpressionである必要があります。
MethodExpressionは以下のようなメソッドを持ちます。
メソッド意味
Object invoke(ELContext context,Object[] aobj)メソッドの呼び出しを行う。
MethodInfo getMethodInfo(ELContext context)メソッドに関数する情報を取得する。
String getExpressionString()EL式を取得する。
boolean isLiteralText()EL式がリテラルテキストから作成されたものの場合にtrueが取得される。


invokeメソッドの第二引数には、呼び出す対象のメソッドの引数を配列で渡します。
上記サンプルでは引数を受け取らないメソッド呼び出しを想定しているためnullをセットしています。



サンプル動作の確認ために、以下のような1つのメソッドが定義されているだけのクラスを作成します。
メッセージを返すだけのシンプルなクラスです。
package sample;

public class SampleMethod {
    
    public String getMessage() {
        return "メソッドの遅延評価のサンプル";
    }
    
}



このタグを使用するにはJSPで以下のように記述します。
<%@ page contentType="text/html; charset=Windows-31J" pageEncoding="Windows-31J" %>
<%@ page import="sample.SampleMethod" %>
<%@ taglib uri="/sample" prefix="s" %>

<%
pageContext.setAttribute("m", new SampleMethod());
%>

<s:sample exp="#{m.getMessage}" />



結果は以下のようになります。
メソッドの遅延評価のサンプル


SampleMethodクラスのメソッド「getMessage」を遅延評価式#{m.getMessage}でタグクラスに渡し、
式をタグ内で評価する事により、メソッドが呼び出されています。





JSPのメニューへ戻る