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なら、コンバータもヴァリデータも呼ばれません。
(おわり)