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 insideProfileBean
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 insideProfileBean
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
insideProfileBean
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
.