decode()とvalidate()の関係


まず、Lifcycleオブジェクト、Sunの参考実装ではLifecycleImpleオブジェクト
が、次の5つのPhaseの各execute()メソッドを次々と呼び出していきます:

    // The set of Phase instances that are executed by the execute() method
    // in order by the ordinal property of each phase
    private Phase phases[] = {
        null, // ANY_PHASE placeholder, not a real Phase
        new RestoreViewPhase(),
        new ApplyRequestValuesPhase(),
        new ProcessValidationsPhase(),
        new UpdateModelValuesPhase(),
        new InvokeApplicationPhase()
    };


最初の「ビュー復元段階」の直後の「値取り出し段階」では、
ApplyRequestValuesPhaseオブジェクトのexecute()が実行され、その中では
ビュールートコンポーネントのprocessDecodes()メソッドが呼び出されます:

        UIComponent component = facesContext.getViewRoot();
        assert (null != component);

        try {
            component.processDecodes(facesContext);


UIViewRootのprocessDecodes()メソッドは、基本的には呼び出しをスーパークラス
のUIComponentBaseに委譲します:

      super.processDecodes(context);


UIComponentBaseのprocessDecodes()メソッドは、次々と自分の子どもの
processDecodes()メソッドを呼び出し、最後に自分のdecode()を呼び出します:

        Iterator kids = getFacetsAndChildren();
        while (kids.hasNext()) {
            UIComponent kid = (UIComponent) kids.next();
            kid.processDecodes(context);
        }

        // Process this component itself
        try {
            decode(context);


コンポーネントが入力コンポーネント(UIInput)だったら、同じくスーパークラス
UIComponentBaseのprocessDecodes()メソッドのprocessDecodes()メソッドを呼び出
すことによって自分のdecode()を行いますが、コンポーネントのimmediate属性が
trueならここでexecuteValidate()を呼び出し、validate()およびValueChangeListener
の実行をしてしまいます:

        super.processDecodes(context);
        
        if (isImmediate()) {
            executeValidate(context);
        }


immediateがtrueでなければ、validate()は、次の「検査処理段階」を担当する
ProcessValidationsPhaseオブジェクトのexecute()メソッドから呼び出される
processValidators()から間接的に呼ばれます:

[UIInput]のprocessValidators():
        super.processValidators(context);
        if (!isImmediate()) { //今度はimmediateがfalseの場合
            executeValidate(context);
        }

[スーパークラスUIComponentBase]のprocessValidators():
        // Process all the facets and children of this component
        Iterator kids = getFacetsAndChildren();
        while (kids.hasNext()) {
            UIComponent kid = (UIComponent) kids.next();
            kid.processValidators(context);
        }

------------------------------------------------------------
さて、話を戻して…
そしてdecode()の最後にはレンダラのdecode()が呼ばれ:

[UIComponentBase]:
        getRenderer(context).decode(context, this);

レンダラのdeocde()はリクエストパラメータから値を取り出して保存します:

[HtmlBasicRendrer]:
        String clientId = component.getClientId(context);
        assert (clientId != null);
        Map requestMap 
         = context.getExternalContext().getRequestParameterMap();
        // Don't overwrite the value unless you have to!
        if (requestMap.containsKey(clientId)) {
            String newValue = requestMap.get(clientId);
            setSubmittedValue(component, newValue);
------------------------------------------------------------

一方validate()は、最初に保存された値のnullチェックをします:

[UIInput]:
        Object submittedValue = getSubmittedValue();
        if (submittedValue == null) {
            return;
        }

ご覧のように、nullなら、コンバータもヴァリデータも呼ばれません。
(おわり)