Managed bean communication

Until now, we have focused especially on the communication between Facelets and managed beans. In this section, we will cover another important aspect regarding JSF communication—managed beans communication. We will discuss the following topics:

  • Injecting a managed bean into another bean
  • Communication between managed beans using the application/session map
  • Accessing other managed beans programmatically

Injecting a managed bean into another bean

A managed bean can be injected into another managed bean using @ManagedProperty. For example, let's suppose that you have a managed bean in the session scope that stores a player name and surname, as shown in the following code:

@Named
@SessionScoped
public class PlayersBean implements Serializable{

  private String playerName;
  private String playerSurname;

  public PlayersBean() {
    playerName = "Rafael";
    playerSurname = "Nadal";
  }

//getters and setters
}

Now, let's suppose that you want to have access to this bean's properties from another view scoped bean, named ProfileBean. For this, you can use @ManagedProperty as shown in the following code:

@ManagedBean //cannot be @Named
@ViewScoped
public class ProfileBean implements Serializable{

  private final static Logger logger = Logger.getLogger(PlayersBean.class.getName());
  @ManagedProperty("#{playersBean}")
  private PlayersBean playersBean;
  private String greetings;

  public ProfileBean() {     
  }   

  public void setPlayersBean(PlayersBean playersBean) {
    this.playersBean = playersBean;
  }        
    
  @PostConstruct
  public void init(){
    greetings = "Hello, " + playersBean.getPlayerName() + " " +playersBean.getPlayerSurname() + " !";
  }
    
  public void greetingsAction(){
    logger.info(greetings);
  }
    
}

A Facelet that calls the greetingsAction method will draw something like the following line in the log:

INFO:   Hello, Rafael Nadal !

Note

The presence of the @PostConstruct method is optional, but it is good to know that this is the earliest place where an injected dependency is available.

This example is wrapped into the application named ch2_22.

If you want to use CDI beans, then you can accomplish the same thing as shown in the following code:

@Named
@ViewScoped
public class ProfileBean implements Serializable{

  @Inject
  private PlayersBean playersBean;
  private String greetings;
  ...

This example is wrapped into the application named ch2_30.

Communication between managed beans using the application/session map

Communication between managed beans can be ensured through an application map or a session map, depending on what kind of communication is needed, during multiple browser sessions or during one browser session.

The advantage of using the application/session map is in the fact that multiple beans can communicate with each other independent of their scopes. First, you need to define a helper class that provides two static methods, one for adding a value into the application map and one for deleting a value from the application map, as shown in the following code:

public class ApplicationMapHelper {
    
  public static Object getValueFromApplicationMap(String key) {
    return FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().get(key);
  }  

  public static void setValueInApplicationMap(String key, Object value) {
    FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().put(key, value);
  }    
}

Now, you can improvise a simple scenario: in one managed bean (request scoped), put some values into the application map, and in another managed bean (session scoped), get those values. So, the first bean code is as follows:

@Named
@RequestScoped
public class PlayersBeanSet {  

  public void playerSetAction() {     
    ApplicationMapHelper.setValueInApplicationMap("PlayersBeanSet.name", "Rafael");
    ApplicationMapHelper.setValueInApplicationMap("PlayersBeanSet.surname", "Nadal");
  }
}

The managed beans that extract these values from the application map are given out as follows:

@Named
@SessionScoped
public class PlayersBeanGet implements Serializable{  

  private final static Logger logger = Logger.getLogger(PlayersBeanGet.class.getName());
    
  public void playerGetAction() {    
    String name = String.valueOf(ApplicationMapHelper.getValueFromApplicationMap("PlayersBeanSet.name"));
    String surname = String.valueOf(ApplicationMapHelper.getValueFromApplicationMap("PlayersBeanSet.surname"));
        
    logger.log(Level.INFO, "Name: {0} Surname: {1}", new Object[]{name, surname});
  }
}

This example is wrapped into the application named ch2_24.

Accessing other managed beans programmatically

Sometimes, you may need to access one managed bean from an event listener class or another managed bean. Suppose that we have a managed bean on session scope, named PlayersBean, and one on request scope, named ProfileBean, and you want to programmatically access PlayersBean inside ProfileBean. Supposing that PlayersBean has been created, you can accomplish this task in the following ways:

  • Use the evaluateExpressionGet method inside ProfileBean as follows:
    FacesContext context = FacesContext.getCurrentInstance();
    PlayersBean playersBean = (PlayersBean) context.getApplication().evaluateExpressionGet(context, "#{playersBean}", PlayersBean.class);
    
    if (playersBean != null) {
      //call the PlayersBean method   
    } else {
      logger.info("SESSION BEAN NOT FOUND!");
    }
  • Use the createValueExpression method inside ProfileBean as follows:
    FacesContext context = FacesContext.getCurrentInstance();
    ELContext elcontext = context.getELContext();
    
    PlayersBean playersBean = (PlayersBean) context.getApplication().getExpressionFactory().createValueExpression(elcontext, "#{playersBean}", PlayersBean.class).getValue(elcontext);
    
    if (playersBean != null) {
      //call the PlayersBean method   
    } else {
      logger.info("SESSION BEAN NOT FOUND!");
    }

    In order to make things simpler, when you need to programmatically create a value expression, you can use a simple helper method and pass only the expression and class, as follows:

    private ValueExpression createValueExpression(String exp, Class<?> cls) {
      FacesContext facesContext = FacesContext.getCurrentInstance();
      ELContext elContext = facesContext.getELContext();
      return facesContext.getApplication().getExpressionFactory().createValueExpression(elContext, exp, cls);
    }
  • Use ELResolver inside ProfileBean as follows:
    FacesContext context = FacesContext.getCurrentInstance();
    ELContext elcontext = context.getELContext();
    
    PlayersBean playersBean = (PlayersBean) elcontext.getELResolver().getValue(elcontext, null, "playersBean");
    
    if (playersBean != null) {
      //call the PlayersBean method   
    } else {
      logger.info("SESSION BEAN NOT FOUND!");
    }

Note

The evaluateExpressionGet method is the most common one.

This example is wrapped into the application named ch2_25.