16

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?

rat
  • 2,544
  • 5
  • 21
  • 19

4 Answers4

27

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

Or without the type, but with a @SuppressWarnings:

@SuppressWarnings("unchecked")
public static <T> T findBean(String managedBeanName) {
    FacesContext context = FacesContext.getCurrentInstance();
    return (T) context.getApplication().evaluateExpressionGet(context, "#{" + managedBeanName + "}", Object.class);
}

which can be used as:

Bean bean = findBean("bean");

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
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 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 Jan 12 '10 at 16:18
  • 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 Jan 12 '10 at 16:20
  • WAS = websphere application server Anyway 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 Jan 12 '10 at 16:27
  • 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 Jan 12 '10 at 16:36
  • Didn't read your comment fully before posting, anyway I logged in now and I'll give you a + thanks :D – rat Jan 12 '10 at 16:42
  • Hi BalusC: wouldnt a simple bean injection with `@ManagedProperty` will solve the OP problem? – Thang Pham May 09 '12 at 15:53
  • 1
    @Thang: The OP mentioned *"Sometimes it becomes necessary to access these instances in code (rather than just in JSF)"*, so I understood that injecting it as managed property isn't an option for some reason. Also note OP's comment on McDowell's answer, the reason seems to be "lazy loading". – BalusC May 09 '12 at 15:56
  • @BalusC Is the answer given here really correct? After all, the thread starter asked for "missing" session beans while 'context.getApplication().createValueBinding' appears to create beans in scope "application", isn't it? – wh81752 Dec 02 '14 at 15:27
  • It works fine, but I want to know ¿what is the difference between this method and using @ManagedProperty("bean")? – Pedro García Medina Mar 30 '15 at 21:42
  • @Pedro: The one is JSF 1.x the other is JSF 2.x. Pay carefully attention to dates and versions. – BalusC Mar 31 '15 at 05:50
3

What about this solution:

public static Object getBean(String beanName)
{          
    Object returnObject = FacesContext.getCurrentInstance().getELContext().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName);  
    if (returnObject == null)  
        System.out.println("Bean with name " + beanName + " was not found. Check the faces-config.xml file if the given bean name is ok.");          
    return returnObject;
}

By this way you can even avoid the Bean.class parameter.

Vic
  • 632
  • 6
  • 15
  • This is a good technique, I like this better. This also in mention on Oleg blog http://ovaraksin.blogspot.com/2011/11/5-useful-methods-jsf-developers-should.html +1 – Thang Pham Mar 04 '12 at 23:16
0

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
  • 107,573
  • 31
  • 204
  • 267
  • Am using the injection already, needs to be more lazy in this instance but thx :) – rat Jan 12 '10 at 16:17
0

Question: will using

FacesContext context = FacesContext.getCurrentInstance();

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

cause a new Bean to be instantiated each time the code runs through these statements? Or will it simply refer to the same instance initially created?

Community
  • 1
  • 1
Sean
  • 971
  • 4
  • 12
  • 21