WicketとJSF 2.0をくらべてみる

同じアプリを書くのが一番わかりやすいので同じコンポーネント志向フレームワークを比べてみる。

内容は足し算と引き算をするアプリ。2つのボタンがあるというのがポイント。

どちらも設定のXMLとかいらないのが面白い。

Wicket

テンプレート。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns:wicket>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Calc</title>
        <link rel="stylesheet" type="text/css" href="style.css"/>
    </head>
    <body>
        <form wicket:id="form">
            <input type="text" wicket:id="data1"/>
            <input type="submit" value="+" wicket:id="add"/>
            <input type="submit" value="−" wicket:id="sub"/>
            <input type="text" wicket:id="data2"/><span wicket:id="label"/>
        </form>

    </body>
</html>

コード。

package calctest;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.PropertyModel;

public final class Calc extends WebPage {

    private Integer a;
    private Integer b;
    private Integer result;

    public Integer getA() {
        return a;
    }

    public void setA(Integer a) {
        this.a = a;
    }

    public Integer getB() {
        return b;
    }

    public void setB(Integer b) {
        this.b = b;
    }

    public Integer getResult() {
        return result;
    }

    public void setResult(Integer result) {
        this.result = result;
    }

    public Calc() {
        form.add(label);
        form.add(data1);
        form.add(data2);
        form.add(add);
        form.add(sub);
        add(form);
    }

    Form form = new Form("form");
    Label label = new Label("label", new PropertyModel<Integer>(this, "result"));
    TextField<Integer> data1 = new TextField<Integer>("data1", new PropertyModel<Integer>(this, "a"));
    TextField<Integer> data2 = new TextField<Integer>("data2", new PropertyModel<Integer>(this, "b"));

    //--------------------------------------------------------------
    //足し算
    //--------------------------------------------------------------
    Button add = new Button("add") {
        @Override
        public void onSubmit() {
            result = a + b;
        }
    };
    //--------------------------------------------------------------
    //引き算
    //--------------------------------------------------------------
    Button sub = new Button("sub") {
        @Override
        public void onSubmit() {
            result = a - b;
        }
    };
}

実行
「+」を押したとき。
http://shin.cside.com/diary/2009/0906-01.png
「−」を押したとき。
http://shin.cside.com/diary/2009/0906-02.png

JSF 2.0版

テンプレート。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <body>
        <form jsfc="h:form">
            <input type="text" jsfc="h:inputText" value="#{calc.data1}"/>
            <input type="submit" value="+" jsfc="h:commandButton" action="#{calc.add}"/>
            <input type="submit" value="−" jsfc="h:commandButton" action="#{calc.sub}"/>
            <input type="text" jsfc="h:inputText" value="#{calc.data2}"/><span jsfc="h:outputText" value="#{calc.result}"/>
        </form>
    </body>
</html>

コード。

package managed;

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ViewScoped
@ManagedBean(name = "calc")
public class Calc implements Serializable{

    private Integer data1;
    private Integer data2;
    private Integer result;

    public Integer getData1() {
        return data1;
    }

    public void setData1(Integer data1) {
        this.data1 = data1;
    }

    public Integer getData2() {
        return data2;
    }

    public void setData2(Integer data2) {
        this.data2 = data2;
    }

    public Integer getResult() {
        return result;
    }

    public void setResult(Integer result) {
        this.result = result;
    }

    //--------------------------------------------------------------
    //足し算
    //--------------------------------------------------------------
    public String add() {
        result = data1 + data2;
        return null;
    }
    //--------------------------------------------------------------
    //引き算
    //--------------------------------------------------------------
    public String sub() {
        result = data1 - data2;
        return null;
    }
}

実行結果は同じなので省略。

思ったこと

WicketのほうがプレーンなHTMLに近い。あくまでもJSF 2.0ではjsfc属性を使おうがコンポーネントをHTMLに偽装しているということで、マッピングされるべきコンポーネントがテンプレート側にかいてある必要がある。

JSFは1.0からテンプレート志向で、テンプレートによって画面遷移も全て処理する。そしてそのテンプレートから呼び出されるBeansがなんであるか、というマッピングをするのである。まずテンプレートありきであって最悪コードは一切なくても画面遷移含めて処理は可能。その場合ロジックはないので意味はないけど。

とはいえWicketもテンプレートの構造を意識する必要がある。画面の構成がかわるとコンポーネントツリーべったりなためコードの修正も入ることになるはず。JSFは個々の値をフラットにマッピングする(もちろん結果的に階層構造であってもよいし、コンポーネントバインディングを使えばWicketに近くなるかも)

モデルとのマッピングをテンプレート側に持っているか、コード側で保持するかが一番大きな違いで、どちらも複数ボタンの対応がしっかりやれているのがわかると思う。

デザイナにプレーンなXHTMLで書いてもらってからのロジック埋め込みはどちらも容易と思われる。

意外と面白かったので今度はCubby 2.0とT2Framework 0.6でも同じものを書いてみるかな。