クラスタリング環境で検証エラーが発生する
開発環境
- JavaSE8
- JavaEE7
- Payara5
- JSF2.2
- Eclipse Oxygen4.7.2
事象
パラメータによって選択肢が変化するラジオボタンがある。
任意の項目を選択しポストすると**「j_idt39: 検証エラー: 値が有効ではありません 」**が発生。
ローカルやシングルインスタンス環境だと発生しない。
原因
プロジェクトの要件でスティッキーセッションを使用せず、通信の都度ランダムにサーバに割り振られていた。
そのためセッション内にBeanが複製されまくり、その中には初期値のない(null)のラジオボタンの選択肢リストが存在した。
ポストしたときに運悪くリストがnullのBeanに当たった時に検証エラーが発生していた。
問題のソース
XHTML
<form jsf:id="form" jsf:prependId="false">
<h:selectOneRadio name="choiceName" value="#{choiceBean.choiceName}" styleClass="radio_list">
<f:selectItems value="#{choiceBean.choiceList}" var="prize" itemLabel="#{item.labelName}" itemValue="#{item}" />
</h:selectOneRadio>
<button jsf:action="#{pageControlBean.toConfirm()}" class="btn_orange">
次へ
</button>
<span jsfc="h:messages" class="form_error_text" />
</form>
Bean
@Named
@SessionScoped
public class ChoiceBean implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull
@Getter @Setter
private ChoiceType choiceName;
@Getter @Setter
private List<ChoiceType> choiceList;
}
Enum
public enum ChoiceType {
TYPE1("タイプ1", 0),
TYPE2("タイプ2", 1),
TYPE3("タイプ3", 2);
@Getter
private final String labelName;
@Getter
private final int index;
private ChoiceType(String labelName, int index) {
this.labelName = labelName;
this.index = index;
}
}
解決
コンストラクタで初期値を設定してやる。
Bean
@Named
@SessionScoped
public class ChoiceBean implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull
@Getter
@Setter
private PrizeType choiceName;
@Getter
@Setter
private List<ChoiceType> choiceList;
/**
* Constructor
* NotNull変数の初期値設定
*/
public ChoiceBean() {
choiceList = new ArrayList<>();
choiceList.add(ChoiceType.TYPE1);
choiceList.add(ChoiceType.TYPE2);
choiceList.add(ChoiceType.TYPE3);
}
}
調査のコツ
最終的にセッションの中身が見えるIDE(有料版Intellijとか)で調査してbeanの複製が分かった。
JavaEEだとNetBeansでも見れるそうですね。