Использование JSTL / основных тегов портит ViewScoped Bean - PullRequest
1 голос
/ 18 мая 2011

Я думаю, что столкнулся с ошибкой в ​​Mojarra 2.1.0.Может быть, я что-то пропустил, но, черт побери, могу это увидеть.

Я полагаюсь на множество @ViewScoped-компонентов для сохранения состояния, в то время как браузер выполняет AJAX на сервере.Я обнаружил, что при использовании определенных тегов bean-компонент @ViewScoped начинает восстанавливаться, когда это не должно быть.Вот мой тестовый пример поддержки:

/*
 * TestStuff.java
 */
package test;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

/**
 * Backing bean for test.xhtml -- working out AJAX/SVG connection
 *
 */

@ManagedBean 
@ViewScoped
public class TestStuff implements Serializable {

private int counter = 0;

public TestStuff() {
    log("TestStuff(): {0}", this);
}

public String getRandomNumber() { 
    int i = (int) (Math.random() * 1000000.0);
    return String.format("%d", i);
}

public int getCounter() { return counter; }

public List<String> getStuff() {
    return Arrays.asList("big", "bad", "wolf");
}

public void pushButton(ActionEvent evt) {
    log("TestStuff.pushButton({0}): {1}", 
            new Object[] { evt, ++counter });
}

}

А вот страница JSF Facelets, которая использует его:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.prime.com.tr/ui"
  xmlns:ui="http://java.sun.com/jsf/facelets"  
  xmlns:f="http://java.sun.com/jsf/core" 
  xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
    <title>Test Page</title>
</h:head>
<h:body>
    <h1>Test Page</h1>
    <p>If you are reading this text, the server
        is not properly configured.</p>
    <ui:composition id="compRoot" template="/template5.xhtml">

        <ui:define name="content">
            <h1>Test</h1>
            <h:form id="formTest">

                <p:commandButton value="Do Me" 
                                 actionListener="#{testStuff.pushButton}"
                                 update="testUpdate" />

                <p:panel id="testUpdate" >
                    <h:outputText value="Random output is: " />
                    <h:outputText
                        value="#{testStuff.randomNumber}"
                        />
                    <h:outputText value=" Counter is: "/>
                    <h:outputText 
                        value="#{testStuff.counter}"
                        />
                </p:panel>

                <h:panelGrid columns="5" border="1" >
                    <c:forEach items="#{testStuff.stuff}" var="x">
                        <h:outputText value="#{x}" />
                    </c:forEach>
                </h:panelGrid>                  

            </h:form>
        </ui:define>
    </ui:composition>
</h:body>
</html>

Так вот, что идет не так.Когда вы нажимаете командную кнопку «Do Me», каждый раз создается новый экземпляр поддерживающего компонента, как если бы это был компонент @RequestScoped.Я могу видеть это через вызов log () в конструкторе.

Если вы измените bean-компонент на @SessionScoped, этого не произойдет.Вы получаете один экземпляр компонента независимо от того, сколько раз нажата кнопка.

ОДНАКО - если оставить его как @ViewScoped и вынуть элемент c: foreach иего содержимое теперь больше не создает экземпляры компонента при каждом щелчке.Другими словами, теперь он работает как положено.

Это ошибка мохарры или я здесь что-то не так делаю?

1 Ответ

2 голосов
/ 18 мая 2011

Это известная «ошибка»: выпуск 1665 . Это проблема куриного яйца в отношении частичного сохранения состояния.

В вашем случае, однако, вы также можете просто использовать <ui:repeat>.

<ui:repeat value="#{testStuff.stuff}" var="x">
    <h:outputText value="#{x}" />
</ui:repeat>

Лучше всего избегать использования тегов JSTL при использовании @ViewScoped. Единственная альтернатива - отключить частичное сохранение состояния с помощью параметра контекста в web.xml:

<context-param>
    <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
    <param-value>false</param-value>
</context-param>

Но это делает взгляды более запоминающимися.

...