JSF NumberFormatException with f:setPropertyActionListener

1k views Asked by At

I'm getting this error with f:setPropertyActionListener and i can't figure out why:

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; }
}

MyTable Bean:

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

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

This is the 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>

I'm using Eclipse Luna (Java EE IDE) with Tomcat 8 and JSF 2.2.11 (mojarra). Any hints are accepted, thank you!

2

There are 2 answers

1
kolossus On BEST ANSWER

You kind of coded your self into a corner with your fancy bean implementation. Take a look at the processing steps for the f:setActionPropertyListener. Your code is choking at step 3:

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

for the following reasons:

  1. The EL processor has determined that myTable is a List. Because of this, it has delegated the evaluation of the expression myTable.selectedItem to the javax.el.ListELResolver class

  2. The ELResolver, on encountering the myTable base object, determines it's a List and automatically assumes that the following string is referring to a list index, i.e. myTable.selectedItem, where selectedItem is supposed to be a list index (per the EL specification, the [] and . are interchangeable for lists). You can see it in action 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, you have the following comment:

    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

"property argument" here is referring to the selectedItem portion of your expression

  1. The EL processor now attempts to convert the string selectedItem to an integer (to be used as a list index) which in turn explodes in a 500

You'll make your work a whole lot easier by not combining your data structure and your backing bean, like Rami. Q suggested. Much cleaner that way IMO

1
Rami.Q On

my Answer should be a comment, but its too long for that, so i write it as an answer.

i see some "ERRORS" in your code:

  1. ALL JSF Beans & objects have to be Serializable
  2. if you use Generic Types, they should be Serializable TOO: public class GenericObject<T extends Serializable> implements Serializable {...}

  3. Setter & Getter of a JSF Object should be like (this.attr = ...;):
    public void setSelectedItem(E value) { this.selectedItem = value;}

  4. be sure that you import the managedBean correctly: import javax.faces.bean.ManagedBean;

  5. instead of <h:dataTable var="item" value="#{myTable}"> you should use <h:dataTable var="item" value="#{myTable.items}">

    and declare items as List Attribute of your bean with getter and setter