MyFaces 1.0.9 のStringArrayConverterのgetAsObjectメソッド その2
id:yone098さんからコメントをもらったので、
s2-jsf-example-1.0.28をベースに再現できるか試してみたらできたので手順を示しておきます。ご参考まで。
ちなみに職場の環境でS2JSFやMyFacesのバージョンを上げて試してはいないです。
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)