2010-11-22

Getters called multiple times in JSF

In JSF, getters of your beans might be called multiple times per request - it’s a fact. Therefore making a data source call from the getter will have a negative impact on your performance.

Suppose you have a page with a form on it. The user fills and submits the form. There are two scenarios possible - submit success or failure. The expensive call could be acquiring a list of options to choose from on the form.

  1. The user opens the page.
  2. Make just one expensive database call. I.e. don’t make the same call twice.
  3. The user fills and submits the form.
  4. Display the success page, do not make the expensive database call.

  1. The user opens the page.
  2. Make just one expensive database call. I.e. don’t make the same call twice.
  3. The user fills and submits the form.
  4. Validation error occurs. Return to the form page and make the expensive call (to reload the list of options, for instance).

For these two scenarios putting the expensive database call in the constructor or getter will not work. You will either get too many calls or too few.

Solution


And here is the solution.

package me.m1key.sample.singlecall;

import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
// ...

@Named
@RequestScoped
public class UserBean {

   @Inject
   private FacesContext facesContext;

   public List<String> getUsernames() {
       if (facesContext.getRenderResponse()) {
           System.out.println("Expensive call...");
       }
       List<String> usernames = new ArrayList<String>();
       usernames.add("Michal");
       usernames.add("Ilinka");
       return usernames;
   }

This part does the trick:
if (facesContext.getRenderResponse()) {
   // Expensive stuff
}

Interested in how to inject FacesContext?

You can download sample code (a Maven app) that works on JBoss 6 M5.

1 comment: