f:setPropertyActionListener 的 JSF NumberFormatException

JSF NumberFormatException with f:setPropertyActionListener

我在使用 f:setPropertyActionListener 时遇到此错误,我不明白为什么:

HTTP Status 500 - For input string: "selectedItem"

exception:
javax.servlet.ServletException: For input string: "selectedItem"
javax.faces.webapp.FacesServlet.service(FacesServlet.java:667)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

root cause:
java.lang.NumberFormatException: For input string: "selectedItem"
java.lang.NumberFormatException.forInputString(Unknown Source)
java.lang.Integer.parseInt(Unknown Source)
java.lang.Integer.parseInt(Unknown Source)
javax.el.ListELResolver.coerce(ListELResolver.java:157)
javax.el.ListELResolver.getType(ListELResolver.java:50)
com.sun.faces.el.DemuxCompositeELResolver._getType(DemuxCompositeELResolver.java:215)
com.sun.faces.el.DemuxCompositeELResolver.getType(DemuxCompositeELResolver.java:242)
org.apache.el.parser.AstValue.getType(AstValue.java:60)
org.apache.el.ValueExpressionImpl.getType(ValueExpressionImpl.java:168)
com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:98)
com.sun.faces.facelets.tag.jsf.core.SetPropertyActionListenerHandler$SetPropertyListener.processAction(SetPropertyActionListenerHandler.java:209)
javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:813)
javax.faces.component.UICommand.broadcast(UICommand.java:300)
javax.faces.component.UIData.broadcast(UIData.java:1108)
javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:654)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

Table Class:

// imports omitted
public class Table<E> extends ArrayList<E> {

    private E selectedItem;

    public E getSelectedItem() { return selectedItem; }

    public void setSelectedItem(E value) { selectedItem = value; }
}

我的Table豆子:

// Imports omitted
@ManagedBean
@ViewScoped
public class MyTable extends Table<File> {

    @PostConstruct
    public void initBean() {
        // Loading some files into the list
    }
}

这是 XHTML:

<html> <!-- Namespaces and stuff omitted -->
    <h:head>...</h:head>
    <h:body>
      <h:form>
        <h:dataTable var="item" value="#{myTable}">
          <h:column>
            <h:commandButton value="Try Me!">
              <f:setPropertyActionListener value="#{item}" target="#{myTable.selectedItem}"/>
                <!-- I'm getting a warning from eclipse here: property not found -->
            </h:commandButton>
          </h:column>
        </h:dataTable>
      </h:form>
    </h:body>
</html>

我将 Eclipse Luna (Java EE IDE) 与 Tomcat 8 和 JSF 2.2.11 (mojarra) 一起使用。接受任何提示,谢谢!

我的答案应该是评论,但它太长了,所以我把它写成答案。

我在你的代码中看到一些 "ERRORS":

  1. 所有 JSF Bean 和对象都必须是可序列化的
  2. 如果您使用通用类型,它们也应该是可序列化的: public class GenericObject<T extends Serializable> implements Serializable {...}

  3. JSF 对象的
  4. Setter & Getter 应该像 (this.attr = ...;) :
    public void setSelectedItem(E value) { this.selectedItem = value;}

  5. 确保您正确导入了 managedBean: import javax.faces.bean.ManagedBean;

  6. 而不是 <h:dataTable var="item" value="#{myTable}"> 你应该使用 <h:dataTable var="item" value="#{myTable.items}">

    并使用 getter 和 setter

  7. items 声明为您的 bean 的列表属性

您使用花哨的 bean 实现将自己编码到了一个角落。看看 the processing steps for the f:setActionPropertyListener。您的代码在第 3 步阻塞:

If the value of the "value" expression is not null, call getType() on the "value" and "target" ValueExpressions to determine their property types

原因如下:

  1. EL 处理器已确定 myTableList。因此,它已将表达式 myTable.selectedItem 的计算委托给 javax.el.ListELResolver class

  2. ELResolver 在遇到 myTable 基础对象时,确定它是一个 List 并自动假定以下字符串引用列表索引,即 myTable。selectedItem,其中 selectedItem 应该是列表索引(根据 EL 规范,[]. 对于列表是可互换的)。您可以看到它的实际效果 here. While it may not be immediately apparent in the tomcat source, if you check the comment in a similar implementation in Jboss for example,您有以下评论:

    If the base object is a list, returns the value at the given index. The index is specified by the property argument, and coerced into an integer

"属性 参数" 这里指的是你表达式的 selectedItem 部分

  1. EL 处理器现在尝试将字符串 selectedItem 转换为整数(用作列表索引),然后在 500
  2. 中展开

通过不将数据结构和辅助 bean 结合起来(如 Rami),您的工作将变得更加轻松。问建议。 IMO

这样更干净