jsfelbracketspropertynotfoundexception

javax.el.PropertyNotFoundException: Target Unreachable, 'BracketSuffix' returned null


I am trying to insert multiple IPs in a List<String> using a simple example. But I am getting following error.

javax.el.PropertyNotFoundException: Target Unreachable, 'BracketSuffix' returned null

Here is my JSF 2.2 page:

<h:form id="form">
    <ui:repeat value="#{exampleBean.ipAddresses}" var="s"
        varStatus="status">
        <h:inputText value="#{exampleBean.ipAddresses[status.index]}" />
    </ui:repeat>
    <h:inputText value="#{exampleBean.newIp}" />
    <h:commandButton value="Add" action="#{exampleBean.add}" />
    <h:commandButton value="Save" action="#{exampleBean.save}" />
</h:form>

And here is my backing bean:

@ManagedBean
@ViewScoped
public class ExampleBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private List<String> ipAddresses;
    private String newIp;

    @PostConstruct
    public void init() {
        ipAddresses= new ArrayList<String>();
    }

    public String save() {
        System.out.println(ipAddresses.toString());
        return null;
    }

    public void add() {
        ipAddresses.add(newIp);
        newIp = null;
    }

    public List<String> getIpAddresses() {
        return ipAddresses;
    }

    public String getNewIp() {
        return newIp;
    }

    public void setNewIp(String newIp) {
        this.newIp = newIp;
    }

}

How is this caused and how can I solve it?


Solution

  • javax.el.PropertyNotFoundException: Target Unreachable, 'BracketSuffix' returned null

    The exception message is wrong. This is a bug in the EL implementation being used by the server. What it really meant here in your specific case is:

    javax.el.PropertyNotFoundException: Target Unreachable, 'ipAddresses[status.index]' returned null

    In other words, there's no such item in the array list. This suggests that the bean got recreated on form submit and therefore reinitializes everything to default. It thus behaves like a @RequestScoped one. Most likely you imported the wrong @ViewScoped annotation. For a @ManagedBean, you need to make sure that the @ViewScoped is imported from the very same javax.faces.bean package, and not thus the JSF 2.2-introduced javax.faces.view one which is specifically for CDI @Named beans.

    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ViewScoped;
    

    See also:


    Update: as per the comments, you're using WebSphere 8.5 which usually ships with an ancient MyFaces 2.0.x version. I reproduced your problem with MyFaces 2.0.5. Its <ui:repeat> failed to remember its view state for iteration status, that's why your construct still fails even though you're properly using a @ViewScoped bean. I could work around it by using <c:forEach> instead.

    <c:forEach items="#{exampleBean.ipAddresses}" var="s" varStatus="status">
        ...
    </c:forEach>
    

    The alternate solution (apart from upgrading MyFaces to a more recent/decent version, obviously) would be to wrap the immutable String in a mutable javabean such as

    public class IpAddress implements Serializable {
        private String value;
        // ...
    }
    

    so that you can use List<IpAddress> instead of List<String> and thus you don't need the varStatus anymore which triggered the MyFaces bug.

    private List<IpAddress> ipAddresses;
    private IpAddress newIp;
    
    @PostConstruct
    public void init() {
        ipAddresses= new ArrayList<IpAddress>();
        newIp = new IpAddress();
    }
    

    <ui:repeat value="#{exampleBean.ipAddresses}" var="ipAddress">
        <h:inputText value="#{ipAddress.value}" />
    </ui:repeat>
    <h:inputText value="#{exampleBean.newIp.value}" />