Get JSF managed bean by name in any Servlet related class
I'm trying to write a custom servlet (for AJAX/JSON) in which I would like to reference my @ManagedBeans
by name. I'm hoping to map:
http://host/app/myBean/myProperty
to:
@ManagedBean(name="myBean")
public class MyBean {
public String getMyProperty();
}
Is it possible to load a bean by name from a regular se开发者_如何学Pythonrvlet? Is there a JSF servlet or helper I could use for it?
I seem to be spoilt by Spring in which all this is too obvious.
In a servlet based artifact, such as @WebServlet
, @WebFilter
and @WebListener
, you can grab a "plain vanilla" JSF @ManagedBean @RequestScoped
by:
Bean bean = (Bean) request.getAttribute("beanName");
and @ManagedBean @SessionScoped
by:
Bean bean = (Bean) request.getSession().getAttribute("beanName");
and @ManagedBean @ApplicationScoped
by:
Bean bean = (Bean) getServletContext().getAttribute("beanName");
Note that this prerequires that the bean is already autocreated by JSF beforehand. Else these will return null
. You'd then need to manually create the bean and use setAttribute("beanName", bean)
.
If you're able to use CDI @Named
instead of the since JSF 2.3 deprecated @ManagedBean
, then it's even more easy, particularly because you don't anymore need to manually create the beans:
@Inject
private Bean bean;
Note that this won't work when you're using @Named @ViewScoped
because the bean can only be identified by JSF view state and that's only available when the FacesServlet
has been invoked. So in a filter which runs before that, accessing an @Inject
ed @ViewScoped
will always throw ContextNotActiveException
.
Only when you're inside @ManagedBean
, then you can use @ManagedProperty
:
@ManagedProperty("#{bean}")
private Bean bean;
Note that this doesn't work inside a @Named
or @WebServlet
or any other artifact. It really works inside @ManagedBean
only.
If you're not inside a @ManagedBean
, but the FacesContext
is readily available (i.e. FacesContext#getCurrentInstance()
doesn't return null
), you can also use Application#evaluateExpressionGet()
:
FacesContext context = FacesContext.getCurrentInstance();
Bean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", Bean.class);
which can be convenienced as follows:
@SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
FacesContext context = FacesContext.getCurrentInstance();
return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}
and can be used as follows:
Bean bean = findBean("bean");
See also:
- Backing beans (@ManagedBean) or CDI Beans (@Named)?
I use the following method:
public static <T> T getBean(final String beanName, final Class<T> clazz) {
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(elContext, null, beanName);
}
This allows me to get the returned object in a typed manner.
Have you tried an approach like on this link? I'm not sure if createValueBinding()
is still available but code like this should be accessible from a plain old Servlet. This does require to bean to already exist.
http://www.coderanch.com/t/211706/JSF/java/access-managed-bean-JSF-from
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
// May be deprecated
ValueBinding binding = app.createValueBinding("#{" + expr + "}");
Object value = binding.getValue(context);
You can get the managed bean by passing the name:
public static Object getBean(String beanName){
Object bean = null;
FacesContext fc = FacesContext.getCurrentInstance();
if(fc!=null){
ELContext elContext = fc.getELContext();
bean = elContext.getELResolver().getValue(elContext, null, beanName);
}
return bean;
}
I had same requirement.
I have used the below way to get it.
I had session scoped bean.
@ManagedBean(name="mb")
@SessionScopedpublic
class ManagedBean {
--------
}
I have used the below code in my servlet doPost() method.
ManagedBean mb = (ManagedBean) request.getSession().getAttribute("mb");
it solved my problem.
I use this:
public static <T> T getBean(Class<T> clazz) {
try {
String beanName = getBeanName(clazz);
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().evaluateExpressionGet(facesContext, "#{" + beanName + "}", clazz);
//return facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(), null, nomeBean);
} catch (Exception ex) {
return null;
}
}
public static <T> String getBeanName(Class<T> clazz) {
ManagedBean managedBean = clazz.getAnnotation(ManagedBean.class);
String beanName = managedBean.name();
if (StringHelper.isNullOrEmpty(beanName)) {
beanName = clazz.getSimpleName();
beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
}
return beanName;
}
And then call:
MyManageBean bean = getBean(MyManageBean.class);
This way you can refactor your code and track usages without problems.
精彩评论