views:

1061

answers:

2

Is it possible to have a JSF managed bean be automatically created?

For example I have several session scoped beans. Sometimes it becomes necessary to access these instances in code (rather than just in JSF) this is done by:

PageBean pageBean = (PageBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("pages");

However if no page has already been visited which calls to '#{pages}' this resolves to null ... is there anyway to get JSF to create a bean when the scope 'begins'? So in this case ideally when a user session begins the 'pages' bean would be instantiated in the session immediately?

+6  A: 

Use Application#evaluateExpressionGet() instead. It will create bean when not done yet.

FacesContext context = FacesContext.getCurrentInstance();
Bean bean = (Bean) context.getApplication().evaluateExpressionGet(context, "#{bean}", Bean.class);

Where "bean" is the managed bean name and Bean.class is the appropriate backing bean class.

You can if necessary wrap this up in a helper method so that casting is unnecessary (the JSF boys didn't take benefit of generics and the Class parameter in evaluateExpressionGet):

public static <T> T findBean(String managedBeanName, Class<T> beanClass) {
    FacesContext context = FacesContext.getCurrentInstance();
    return beanClass.cast(context.getApplication().evaluateExpressionGet(context, "#{" + managedBeanName + "}", beanClass);
}

which can be used as:

Bean bean = findBean("bean", Bean.class);

Update: the above is by the way JSF 1.2 specific. Here's the way for JSF 1.1 or older, using the currently deprecated Application#createValueBinding():

FacesContext context = FacesContext.getCurrentInstance();
Bean bean = (Bean) context.getApplication().createValueBinding("#{bean}").getValue(context);
BalusC
Thx for this, my IDE is being lame with the class loading on this but I believe it's the right way of doing it ... stupid WAS eclipse and its built in libs.
rat
WAS? My answer is by the way targeted on JSF 1.2 (which is already almost 4 years old now). WAS used to ship with legacy JSF 1.1 for a very long time until with 6.1 around 2007. I'll edit my answer and add the JSF 1.1 way soon.
BalusC
WAS = websphere application serverAnyway ya I figured it must be 1.2 since WAS includes 1.1 libs and it wasn't showing the method as valid, I changed the class loading around though and now its working fine thanks again :D
rat
Yes, I know what WAS means :) I even mentioned that it used to ship with JSF 1.1 by default. Glad you got it to work. Don't forget to mark the answer accepted.
BalusC
Didn't read your comment fully before posting, anyway I logged in now and I'll give you a + thanks :D
A: 

One mechanism is to inject the bean into the bean you want to refer to into another bean, as demonstrated with expensiveBean here:

  <managed-bean>
    <managed-bean-name>requestBean</managed-bean-name>
    <managed-bean-class>lifetime.RequestBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    <managed-property>
      <property-name>cachedAsset</property-name>
      <property-class>lifetime.ExpensiveBean</property-class>
      <value>#{expensiveBean}</value>
    </managed-property>
  </managed-bean>

This isn't very "lazy", but it can be convenient.

McDowell
Am using the injection already, needs to be more lazy in this instance but thx :)
rat