javax.faces.view.ViewScoped bean и проблема с несколькими вкладками - PullRequest
0 голосов
/ 24 сентября 2018

В приложении 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() вызывает NPE в _model.getId() на других страницах после первого выполнения.

Между тем подход, подобный приведенному ниже, работает нормально:

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

Я записал видео 30сек с проблемой

Также пример проекта опубликован на GitHub

В чем причина NPE,и каков наиболее правильный способ использования навигации после некоторых действий в таком сценарии?

Спасибо!

PS Темы типа В чем разница между перенаправлением и навигацией /вперед и когда использовать что? Я уже прочитал, но ответа на мой вопрос пока не найдено.

Обновление 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 голосов
/ 02 ноября 2018

Я также столкнулся с этим после перехода от Wildfly 11 -> Wildfly 14 (Mojarra 2.2.13.SP4 -> 2.3.5.SP2)

Этот демонстрационный проект работает на Wildfly 11, но не работаетна Wildfly 14.

Может показаться, что ссылки в ViewMap удалены, но фактические компоненты ViewScoped не уничтожены.

Я открыл https://issues.jboss.org/browse/WFLY-11275, чтобы, надеюсь, отследить этовниз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...