简体   繁体   中英

JSF Managed Bean auto-create?

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?

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

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.

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.

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM