Question

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;
    }

}
Was it helpful?

Solution

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.

OTHER TIPS

It can be called from different phases of the JSF lifecylce. My bet would be the phases RestoreView and then RenderResponse -- I haven't been using JSF lately, so I don't remember this in detail.

You can cache the latest filter pattern and the corresponding clients. You reload the clients only if the filter changed. This way, you solve this particular problem, plus avoid reloading data if the filter didn't change.

private String nameFilterPattern;
private String lastNameFilterPatternLoaded;
private List<Kunde> clients;

public List<Kunde> getKunden(){
    System.out.println("getKunden");
    if( nameFilterPattern.equals( lastNameFilterPatternLoaded ) )
    {
        clients = getApplication().getKunden(getNameFilterPattern());
        lastNameFilterPatternLoaded = nameFilterPattern
    }
    return clients;
}

Or you can use a request bean (instead of session) and make sure you load the data only once per request.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top