Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is BackingBean method called multiple times when requesting facelet?

I'm working and learning about JSF + Facelets these days. I have a BackingBean and a Facelet xHTML page. When I request the facelet-page (only one time) the backing-bean-method is called multiple times.

What could be the reason for this?

I can't see anything special. Thanks in advance.

Here is the facelet:

<?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:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
<ui:composition template="index.xhtml">
    <ui:define name="content">
        <h:form>Name: <h:inputText id="nameFilterPattern" value="#{kundenBackingBean.nameFilterPattern}" /><h:commandButton value="Suchen"/></h:form>
        <h:dataTable var="kunde" value="#{kundenBackingBean.kunden}" rowClasses="rowHighlight, rowOrdinary">
            <h:column> 
                <f:facet name="header">
                    <h:outputText value="Kundennr" />
                </f:facet>
                <h:outputText value="#{kunde.kundenNr}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Name" />
                </f:facet>
                <h:outputText value="#{kunde.name}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Vorname" />
                </f:facet>
                <h:outputText value="#{kunde.vorname}"/>
            </h:column>
            <h:column>
                <h:outputLink>Details</h:outputLink>
            </h:column>
        </h:dataTable>
    </ui:define>
</ui:composition>
</body>
</html>

And here is the backing-bean. The method getKunden is called multiple times:

@ManagedBean
@SessionScoped
public class KundenBackingBean extends AbstractBackingBean {

    private String nameFilterPattern;

    public List<Kunde> getKunden(){
        System.out.println("getKunden");
        return getApplication().getKunden(getNameFilterPattern());
    }

    public String getNameFilterPattern() {
        return nameFilterPattern;
    }

    public void setNameFilterPattern(String nameFilterPattern) {
        System.out.println("Name filter: " + nameFilterPattern);
        this.nameFilterPattern = nameFilterPattern;
    }

}
like image 759
c0d3x Avatar asked Feb 16 '10 10:02

c0d3x


1 Answers

The getters of a bean are just there to access model data from the view side. They can be called multiple times. Usually one or two times, but this can grow up to hundreds of times, especially when also used in UIData components or in other attributes than value (like rendered, disabled, etc). This does normally not harm, as it's just a simple method-invocation and doing expensive data loading logic or calculations is usually not to be done in the getters. Preloading/initializing is usually to be done in the bean constructor and/or bean action methods. Getters should in fact only return the data (if necessary also do lazy loading).

If getApplication().getKunden(getNameFilterPattern()); is doing a pretty expensive task, you should really move it to either the bean constructor, or bean @PostConstruct method, or bean initialization block, or bean action method, or introduce lazy loading pattern in the getter. Here's an example which shows how to do this all:

public class Bean {
    private String nameFilterPattern;
    private List<Kunde> kunden;

    // Load during bean construction.
    public Bean() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR load during @PostConstruct (will be invoked AFTER construction and resource injection.
    @PostConstruct
    public void init() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR during bean initialization (this is invoked BEFORE construction and will apply to ALL constructors).
    {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR during bean action method (invoked from h:commandLink/Button).
    public String submit() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
        return "navigationCaseOutcome";
    }

    // OR using lazy loading pattern in getter method.
    public List<Kunde> getKunden() {
        if (this.kunden == null) 
            this.kunden = getApplication().getKunden(getNameFilterPattern());
        }
        return this.kunden;
    }

In your specific case, I think it's the @PostConstruct (if the nameFilterPattern is to be obtained from a GET request parameter), or just the bean action method (if nameFilterPattern is to be obtained from a POST form input field) is suitable.

To learn more about the JSF lifecycle, you may find this self-practice article useful.

like image 107
BalusC Avatar answered Oct 19 '22 22:10

BalusC