1
votes

In a JSF application (Payara 5.183 based) I am using patterns like below for redirecting user after some action:

@Named
@ViewScoped
public class ModelViewBean implements Serializable {
    private Model _model;
    ...
    public String delete() {
        System.out.println(">> Deleting model with ID: " + _model.getId());
        _appDaoBean.daoDelete(_model);
        return "/main.xhtml?faces-redirect=true";
    }
    ...
}

The issue: in case there are two or more pages were open with different _model objects - action delete() causes NPE in _model.getId() on other pages after first execution.

Meanwhile the approach like below works fine:

@Named
@ViewScoped
public class ModelViewBean implements Serializable {
    private Model _model;
    ...
    public void delete() {
        System.out.println(">> Deleting model with ID: " + _model.getId());
        _appDaoBean.daoDelete(_model);
        FacesContext.getCurrentInstance().getExternalContext().redirect("/main.xhtml");
    }
    ...
}

I have recorded the 30sec video with the issue

Also the sample project is published on the GitHub

What is the reason of the NPE, and what is the most proper way of using navigation after some action in such scenario?

Thank you!

P.S. Topics like What is the difference between redirect and navigation/forward and when to use what? I have already read but no answer for my question found so far.

Update 1:

main.xhtml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:p="http://primefaces.org/ui">

    <h:body>
        <h:form id="f1">

            <h2>Main Page</h2>

            <p:link outcome="/model.xhtml" value="Model1">
                <f:param name="id" value="1"/>
            </p:link>

            <br/>

            <p:link outcome="/model.xhtml" value="Model2">
                <f:param name="id" value="2"/>
            </p:link>

        </h:form>
    </h:body>
</html>

model.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:p="http://primefaces.org/ui">
    <f:view>
        <f:metadata>
            <f:viewParam name="id" value="#{modelViewBean.id}" />
            <f:viewAction action="#{modelViewBean.initModel}" />
        </f:metadata>
        <h:body>
            <h:form id="f1">

                <p:outputLabel value="Model ID: #{modelViewBean.model}" />
                <br/>
                <p:commandButton value="Delete" action="#{modelViewBean.delete()}" process="@this" update="@form" />

            </h:form>
        </h:body>
    </f:view>
</html>

ModelViewBean.java

....
import javax.faces.view.ViewScoped;
....

@Named
@ViewScoped
public class ModelViewBean implements Serializable {

    private static final long serialVersionUID = 6400111954793903238L;

    private String _id;
    private String _model;
    private Date _beanCreateTime;


    @PostConstruct
    private void init() {
        System.out.println(">> @PostConstruct -> init()");
        _beanCreateTime = new Date();
    }


    public String initModel() {
        System.out.println(">> ViewAction -> initModel()");
        if (_id == null || _id.trim().isEmpty()) {
            return "/main.xhtml?faces-redirect=true";
        }
        _model = UUID.randomUUID().toString();
        return null;
    }


    public String delete() {
        System.out.println(">> Deleting model with ID: " + _model.toUpperCase());
        return "/main.xhtml?faces-redirect=true";
    }


    public String getId() {
        return _id;
    }


    public void setId(String id) {
        this._id = id;
    }


    public String getModel() {
        return _model;
    }


    public Date getBeanCreateTime() {
        return _beanCreateTime;
    }
}

NPE:

java.lang.NullPointerException
at local.jsfsample.ModelViewBean.delete(ModelViewBean.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
....

Steps for reproducing the issue:

  1. Open main.xhtml
  2. Open both links in two tabs (Model1 and Model2) simultaneously
  3. Press "Delete" button in the first tab with Model1 - everything fine
  4. Press "Delete" button in the second tab with Model2 - NPE as _model equals null (also I have noticed that @PostConstruct is being triggered as well)

Update 2:

The topic was updated in order to reflect more fundamental cause of the issue. Thanks for links in comments to the similar posts.

1
JSF 2.4 does not exist as an official release. It is a weird (required by Oracle) side effect of moving all Java EE code to Eclipse. Example code (in minimal reproducible example flavour, should be posted inline. And please post the stacktrace with the NPE and explicitly mention on which line the NPE occurs... - Kukeltje
And, are you indeed implying that the NPE doesn't occur when the bean is in a different scope? - BalusC
@BalusC thank you for your question! Based on the usage scenario - I can not use any other scopes, as I need to open two similar pages with different models (entities) simultaneously. Thus trying to workaround usage of the @ViewScoped bean - doesn't really help (even it could work fine). - AndrewG10i
@Kukeltje thank you for your time checking my post! I have posted the exact piece of code that contains a root cause of the issue. Whole sample project code available following the link on GitHub. Stack-trace is pretty plain, nothing special at all. Also, the issue itself becoming super self-explaining by reviewing the short video I have attached. Thank you again for your time! P.S. The issue can be reproduced on the Glassfish 5 with JSF 2.3.2 as well. - AndrewG10i
try with other scopes. Of it fails there too, your title is not right and people might start trting solutiins un wrong directions. And again please post an minimal reproducible example inline - Kukeltje

1 Answers

2
votes

I've run into this as well after moving from Wildfly 11 -> Wildfly 14 ( Mojarra 2.2.13.SP4 -> 2.3.5.SP2 )

This demo project works on Wildfly 11 but fails on Wildfly 14.

It would appears that the references in the ViewMap are removed but the actual ViewScoped beans are not destroyed.

I've opened https://issues.jboss.org/browse/WFLY-11275 to hopefully track this down.