简体   繁体   中英

<ui:repeat> in JSF 2.0 breaks methods execution order

I have very simple JSF 2.0 application (see below). The problem is that when ui:repeat is present, execution order (I check it using breakpoints in debugger) is strange.

After I submit form, SecondBean.initSomething() is called before FirstBean.setFirstFormField() . If I change type of something to String and delete ui:repeat from index.jsf and use just h:outputText then everything works as expected, FirstBean.setFirstFormField() is called before SecondBean.initSomething() .

What I'm doing wrong?

I'm using JDeveloper Studio Edition 11.1.2.2.0 and its stack (WebLogic 10.3.5.0, Java 6 and JSF 2.0).

Here's the code:

index.jsf:

<?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">
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
    <html xmlns="http://www.w3.org/1999/xhtml">
        <h:head></h:head>
        <h:body>
            <h:form>
                <h:panelGrid columns="1">
                    <h:inputText value="#{firstBean.firstFormField}" />
                    <h:commandButton action="#{firstBean.processForm}" value="Submit" />
                </h:panelGrid>
            </h:form>
            <ui:repeat value="#{secondBean.something}" var="variable" >
                <h:outputText value="#{variable}" />
            </ui:repeat>
        </h:body>
    </html>
</f:view>

FirstBean.java:

package test.backing;

import javax.faces.bean.*;
import javax.faces.context.FacesContext;

@ManagedBean
@RequestScoped
public class FirstBean {
    private String firstFormField;
    public FirstBean() {
        super();
    }

    public String processForm() {
        FacesContext facesContext;

        facesContext = FacesContext.getCurrentInstance();

        return facesContext.getViewRoot().getViewId();            
    }

    public void setFirstFormField(String firstFormField) {
        this.firstFormField = firstFormField;
    }

    public String getFirstFormField() {
        return this.firstFormField;
    }
}

SecondBean.java:

package test.backing;

import java.util.*;

import javax.annotation.PostConstruct;

import javax.faces.bean.*;

@ManagedBean
@RequestScoped
public class SecondBean {
    private List<String> something;

    public SecondBean() {

    }

    @PostConstruct
    public void initSomething() {
        this.something = Arrays.asList("abc", "cde");
    }

    public void setSomething(List<String> something) {
        this.something = something;
    }

    public List<String> getSomething() {
        return this.something;
    }
}

faces-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee">

</faces-config>

web.xml:

<?xml version = '1.0' encoding = 'UTF-8'?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
  <context-param>
    <param-name>javax.faces.FACELETS_VIEW_MAPPINGS</param-name>
    <param-value>*.jsf;*.xhtml</param-value>
  </context-param>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
  </servlet-mapping>
</web-app>

What I'm doing wrong?

Nothing. It's working as specified. It's just invoked during restoring the view.

If this is causing a specific problem for you, which is unfortunately not described in detail in the question at all, then a solution needs to be sought in a different direction than depending/relying on some specific execution order of bean construction or getter calls relative to the view. At least, that is what you seem to be targeting at for some reason.


Unrelated to the concrete problem, in that processForm() action method you can also just return null to navigate back to the current view. That's much simpler than the current clumsy approach.

This is how the JSF cycle works. The order is correct...

You need to change the manner you are doing agreeing with the rules of the JSF framework. Learn the phases of the JSF cycle, may this can help you.

您可以使用h:dataTable,它不会在还原阶段填充值,而是在updateModel pahse之后填充值

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM