MyFaces 1.0.9 のStringArrayConverterのgetAsObjectメソッド その2

id:yone098さんからコメントをもらったので、
s2-jsf-example-1.0.28をベースに再現できるか試してみたらできたので手順を示しておきます。ご参考まで。

ちなみに職場の環境でS2JSFMyFacesのバージョンを上げて試してはいないです。

s2-jsf-example-1.0.28のemployeeEdit.htmlを以下のようにする。

<html xmlns:m="http://www.seasar.org/maya"
	m:action="#{employeeEditInitAction.initialize}"
	m:extends="/WEB-INF/layout/layout.html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-31j"/>
<link rel="stylesheet" type="text/css" href="../css/global.css"/>
<title>Employee Management</title>
</head>

<body>
<span m:inject="f:param" m:name="layoutTitle" m:value="Employee Management"/>
<span m:inject="s:insert" m:name="body">

<h2>
<span m:value="Create"
	m:rendered="#{processModeDto.processMode == 1}"
	m:class="display" class="notdisplay">
	Create
</span>
<span m:value="Edit"
	m:rendered="#{processModeDto.processMode == 2}">
	Edit
</span>
</h2>
<span m:inject="h:messages" m:globalOnly="true" m:class="error"/>
<form id="employeeEditForm">
<input type="hidden" m:value="#{employeeDto.versionNo}"
	m:rendered="#{processModeDto.processMode == 2}"/>
<input type="hidden" id="empnoHidden" m:value="#{employeeDto.empno}"
	m:rendered="#{processModeDto.processMode == 2}"/>
<table class="tablebg">
<tr>
    <td class="label">EmployeeNo</td>
    <td>
    	<input id="empno" type="text"
    		m:value="#{employeeDto.empno}"
    		m:class="display right"
    		class="notdisplay"
    		m:required="true"
    		m:rendered="#{processModeDto.processMode == 1}"/>
    	<span m:inject="h:message" m:for="empno" m:class="error"
    		m:rendered="#{processModeDto.processMode == 1}"/>
    	<div class="right" m:rendered="#{processModeDto.processMode == 2}">
    		<span m:value="#{employeeDto.empno != null ? employeeDto.empno : param['employeeEditForm:empnoHidden']}">7788</span>
    	</div>
	</td>
</tr>
<tr>
    <td class="label">EmployeeName</td>
    <td><input id="employeeName" type="text" m:value="#{employeeDto.ename}" m:required="true" value="SCOTT"/>
        <span m:inject="h:message" m:for="employeeName" m:class="error"/>
    </td>
</tr>
<tr>
    <td class="label">Job</td>
    <td><input type="text" m:value="#{employeeDto.job}" value="ANALYST"/></td>
</tr>
<tr>
    <td class="label">Manager</td>
    <td><input id="mgr" type="text" class="right"
    		m:value="#{employeeDto.mgr}" value="7566"/>
    	<span m:inject="h:message" m:for="mgr" m:class="error"/>
    </td>
</tr>
<tr>
    <td class="label">HireDate</td>
    <td><input id="hiredate" type="text"
    		m:value="#{employeeDto.hiredate}" value="1982/12/09"/>
    	<span m:inject="h:message" m:for="hiredate" m:class="error"/>
    </td>
</tr>
<tr>
    <td class="label">Salary</td>
    <td><input id="sal" type="text" class="right"
    		m:value="#{employeeDto.sal}" value="3000"/>
    	<span m:inject="h:message" m:for="sal" m:class="error"/>
    </td>
</tr>
<tr>
    <td class="label">Commission</td>
    <td><input id="comm" type="text" class="right" m:value="#{employeeDto.comm}"/>
    	<span m:inject="h:message" m:for="comm" m:class="error"/>
    </td>
</tr>
<tr>
    <td class="label">Department</td>
    <td><select id="deptno" m:value="#{employeeDto.deptno}"
    		m:items="#{departmentDtoList}"
    		m:itemValue="deptno"
    		m:itemLabel="dname"
    		m:nullLabel="Please select">
			<option value="10">ACCOUNTING</option>
			<option value="20">RESEARCH</option>
			<option value="30">SALES</option>
			<option value="40">OPERATIONS</option>
		</select>
	</td>
	<td><span m:inject="h:message" m:for="deptno" m:class="error"/></td>
</tr>
<tr>
    <td class="label">users</td>
    <td>
        <span m:inject="s:selectManyCheckbox"
    	m:label="users"
        m:value="#{employeeDto.users}"
        m:items="#{selectManyCheckboxBbbItems}">
    </span><br />
    </td>
</tr>
</table>
<input type="button" value="confirm" m:action="#{employeeEditAction.goConfirm}"
	onclick="location.href='employeeConfirm.html'"/>
<input type="button" value="previous"
	m:action="#{employeeEditAction.goPrevious}"
	m:immediate="true"
	onclick="location.href='employeeList.html'"/>
</form>
</span>
</body>
</html>

以下を追加してます。

<tr>
    <td class="label">users</td>
    <td>
        <span m:inject="s:selectManyCheckbox"
    	m:label="users"
        m:value="#{employeeDto.users}"
        m:items="#{selectManyCheckboxBbbItems}">
    </span><br />
    </td>
</tr>

employeeConfirm.htmlは以下のとおり。

<html xmlns:m="http://www.seasar.org/maya"
	m:action="#{employeeConfirmInitAction.initialize}"
	m:extends="/WEB-INF/layout/layout.html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-31j"/>
<link rel="stylesheet" type="text/css" href="../css/global.css"/>
<title>Employee Management</title>
</head>

<body>
<span m:inject="f:param" m:name="layoutTitle" m:value="Employee Management"/>
<span m:inject="s:insert" m:name="body">

<h2>
<span m:value="Create"
	m:rendered="#{processModeDto.processMode == 1}"
	m:class="display" class="notdisplay">
	Create
</span>
<span m:value="Edit"
	m:rendered="#{processModeDto.processMode == 2}">
	Edit
</span>
<span m:value="Delete"
	m:rendered="#{processModeDto.processMode == 3}"
	m:class="display" class="notdisplay">
	Delete
</span>
<span m:value="Inquire"
	m:rendered="#{processModeDto.processMode == 4}"
	m:class="display" class="notdisplay">
	Inquire
</span>
</h2>
<span m:inject="h:messages"
	m:globalOnly="true"
	m:showDetail="true"
	m:class="error"/>

<form>
<input type="hidden" m:value="#{employeeDto.versionNo}"/>
<input type="hidden" m:value="#{employeeDto.empno}"/>
<input type="hidden" m:value="#{employeeDto.ename}"/>
<input type="hidden" m:value="#{employeeDto.job}"/>
<input type="hidden" m:value="#{employeeDto.mgr}"/>
<input type="hidden" m:value="#{employeeDto.hiredate}"/>
<input type="hidden" m:value="#{employeeDto.sal}"/>
<input type="hidden" m:value="#{employeeDto.comm}"/>
<input type="hidden" m:value="#{employeeDto.deptno}"/>
<input type="hidden" m:value="#{employeeDto.dname}"/>
<input type="hidden" m:value="#{employeeDto.users}"/>
<table class="tablebg">
<tr>
    <td class="label">EmployeeNo</td>
    <td class="right"><span m:value="#{employeeDto.empno}">7788</span></td>
</tr>
<tr>
    <td class="label">EmployeeName</td>
    <td><span m:value="#{employeeDto.ename}">SCOTT</span></td>
</tr>
<tr>
    <td class="label">Job</td>
    <td><span m:value="#{employeeDto.job}">ANALYST</span></td>
</tr>
<tr>
    <td class="label">Manager</td>
    <td class="right"><span m:value="#{employeeDto.mgr}">7566</span></td>
</tr>
<tr>
    <td class="label">HireDate</td>
    <td><span m:value="#{employeeDto.hiredate}">1982/12/09</span></td>
</tr>
<tr>
    <td class="label">Salary</td>
    <td class="right"><span m:value="#{employeeDto.sal}">3,000</span></td>
</tr>
<tr>
    <td class="label">Commission</td>
    <td><span m:value="#{employeeDto.comm}"></span></td>
</tr>
<tr>
    <td class="label">Department</td>
    <td><span m:value="#{employeeDto.dname}">ACCOUNTING</span></td>
</tr>
<tr>
    <td class="label">users</td>
    <td><span m:value="#{employeeDto.users}">users</span></td>
</tr>
</table>
<input type="button" value="store"
	m:action="#{employeeConfirmAction.store}"
	m:rendered="#{processModeDto.processMode != 4}"
	onclick="location.href='employeeSearch.html'"/>
<input type="button" value="previous"
	m:action="#{employeeConfirmAction.goPrevious}"
	onclick="location.href='employeeEdit.html'"/>
</form>
</span>
</body>
</html>

以下の2つを追加してます。

<tr>
    <td class="label">users</td>
    <td><span m:value="#{employeeDto.users}">users</span></td>
</tr>
<input type="hidden" m:value="#{employeeDto.users}"/>


EmployeeDtoは下記のとおり。

/*
 * Copyright 2004-2006 the Seasar Foundation and the Others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package examples.jsf.dto;

import examples.jsf.entity.Employee;

public class EmployeeDto extends Employee {

    private static final long serialVersionUID = 1L;

    private String dname;
    
    private String[] users;

    public String[] getUsers() {
		return users;
	}

	public void setUsers(String[] users) {
		this.users = users;
	}

	public EmployeeDto() {
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    protected void setupToString(StringBuffer buf) {
        super.setupToString(buf);
        buf.append(", ");
        buf.append(dname);
    }

}

以下を追加してます。

    private String[] users;

    public String[] getUsers() {
		return users;
	}

	public void setUsers(String[] users) {
		this.users = users;
	}

この状況でemployeeEdit.htmlでチェックボックスに何も選択せずにconfirmボタンを押して、
employeeConfirm.htmlに遷移した後にpreviousボタンで戻るとヌルポが発生します。

スタックトレースは下記のとおりです。

java.lang.NullPointerException
java.util.StringTokenizer.(StringTokenizer.java:146)
java.util.StringTokenizer.(StringTokenizer.java:162)
org.apache.myfaces.convert.StringArrayConverter.getAsObject(StringArrayConverter.java:39)
org.apache.myfaces.renderkit.RendererUtils.getConvertedUIOutputValue(RendererUtils.java:780)
org.apache.myfaces.renderkit.html.HtmlHiddenRenderer.getConvertedValue(HtmlHiddenRenderer.java:79)
javax.faces.component.UIInput.getConvertedValue(UIInput.java:320)
javax.faces.component.UIInput.validate(UIInput.java:296)
javax.faces.component.UIInput.processValidators(UIInput.java:170)
javax.faces.component.UIForm.processValidators(UIForm.java:66)
javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:427)
javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:427)
javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:427)
javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:162)
org.seasar.jsf.component.S2UIViewRoot.processValidators(S2UIViewRoot.java:68)
org.seasar.jsf.lifecycle.LifecycleImpl.processValidations(LifecycleImpl.java:165)
org.seasar.jsf.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:100)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:109)
org.seasar.extension.filter.EncodingFilter.doFilter(EncodingFilter.java:62)
org.seasar.framework.container.filter.S2ContainerFilter.doFilter(S2ContainerFilter.java:60)
org.apache.myfaces.component.html.util.ExtensionsFilter.doFilter(ExtensionsFilter.java:112)