JSTL c: forEach заставляет бин @ViewScoped вызывать @PostConstruct при каждом запросе - PullRequest
8 голосов
/ 16 мая 2010

Опять же, я вижу, что @PostConstruct срабатывает каждый раз, хотя атрибут привязки не используется. Смотрите этот код: -

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h:form>
            <c:forEach var="item" items="#{TestBean.listItems}">
                <h:outputText value="#{item}"/>
            </c:forEach>
            <h:commandButton value="Click" actionListener="#{TestBean.actionListener}"/>
        </h:form>
    </h:body>
</html>

И это самый простой из возможных bean-компонентов в JSF: -

package managedBeans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean(name="TestBean")
@ViewScoped
public class TestBean implements Serializable {

    private List<String> listItems;

    public List<String> getListItems() {
        return listItems;
    }

    public void setListItems(List<String> listItems) {
        this.listItems = listItems;
    }

    public TestBean() {

    }

    @PostConstruct
    public void init(){
        System.out.println("Post Construct fired!");
        listItems = new ArrayList<String>();
        listItems.add("Mango");
        listItems.add("Apple");
        listItems.add("Banana");
    }

    public void actionListener(){
        System.out.println("Action Listener fired!");
    }

}

Видите ли вы какое-либо поведение, которое должно вызывать срабатывание обратного вызова постструктуры каждый раз? Я думаю, что JSF 2.0 очень нестабилен. Если он должен запускать PostConstruct каждый раз, для какой цели служит @ViewScoped. Почему бы не использовать только @RequestScoped? Я думал, что допустил ошибку в своем заявлении. Но когда я создал это самое простое из возможных в JSF, я все еще получаю эту ошибку. Разве я не понимаю сферу применения JSF? или они не проверяют это должным образом? Кроме того, если вы удалите c: forEach и замените его на ui: repeat, тогда он будет работать нормально.

Ожидание ответов, чтобы подтвердить, является ли это ошибкой или намеренно остановить программистов от использования jstl?

1 Ответ

13 голосов
/ 16 мая 2010

Эта проблема имеет те же основания, что и ваш предыдущий вопрос, на который дан ответ: Почему обратный вызов @PostConstruct срабатывает каждый раз, даже если bean-компонент @ViewScoped? JSF .

Это действительно ошибка в JSF2. Это проблема куриного яйца. Бины с областью видимости хранятся в состоянии просмотра JSF. Таким образом, компоненты видимости доступны только после фазы восстановления. Однако JSTL-теги выполняются на этапе восстановления представления, в то время как bean-объекты области видимости пока недоступны. Это приводит к созданию совершенно нового экземпляра bean-объекта области видимости, который затем заменяется реальным bean-объектом области видимости, который был сохранен в восстановленном состоянии представления JSF.

Это сообщается как JSF выпуск 1665 и JSF spec isssue 787 , который исправлен для JSF 2.2 и перенесен в Mojarra 2.1.18. Таким образом, простое обновление до Мохарры 2.1.18 должно подойти.

Если вы не можете выполнить обновление, тогда вам лучше всего использовать JSTL-теги исключительно для bean-компонентов области запроса / сеанса / приложения или искать альтернативные пути для конкретного функционального требования. Вы можете заменить <c:forEach> на <ui:repeat>, как вы уже узнали.

Смотри также:

...