javax.faces.view.ViewScoped bean和多个选项卡问题

时间:2018-09-24 10:35:19

标签: jsf redirect nullpointerexception

在JSF应用程序(基于Payara 5.183)中,我使用以下模式在执行某些操作后重定向用户:

@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";
    }
    ...
}

问题:如果打开两个或多个页面时使用不同的_model对象-操作delete()导致其他页面上_model.getId()中的NPE第一次执行。

与此同时,下面的方法也可以正常工作:

@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");
    }
    ...
}

我已经记录了30sec video with the issue

还有示例项目is published on the GitHub

发生NPE的原因是什么?在这种情况下采取某些措施后,使用导航的最正确方法是什么?

谢谢!

P.S。到目前为止,What is the difference between redirect and navigation/forward and when to use what?之类的主题我都已阅读,但尚未找到答案。

更新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)
....

重现问题的步骤:

  1. 打开main.xhtml
  2. 同时在两个标签(Model1和Model2)中打开两个链接
  3. 在Model1的第一个标签中按“删除”按钮-一切正常
  4. 在Model2-NPE的第二个选项卡中按“删除”按钮,因为_model等于null(我也注意到@PostConstruct也被触发了)

更新2:

该主题已更新,以反映此问题的更根本原因。感谢您对类似文章的评论链接。

1 个答案:

答案 0 :(得分:2)

从Wildfly 11-> Wildfly 14(Mojarra 2.2.13.SP4-> 2.3.5.SP2)迁移后,我也遇到了这个问题

此演示项目可在Wildfly 11上运行,但在Wildfly 14上失败。

似乎已删除了ViewMap中的引用,但并未破坏实际的ViewScoped bean。

我已经打开https://issues.jboss.org/browse/WFLY-11275来希望对此进行跟踪。