101

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 servlet? 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.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
Konrad Garus
  • 50,165
  • 42
  • 145
  • 220
  • I'm not sure if you can use these new annotations outside JSF/EL, but I'd start by looking at the JSR 299 spec: http://jcp.org/en/jsr/detail?id=299 – McDowell Apr 13 '10 at 22:22
  • Other people having problems with similar issues can also check https://bpcatalog.dev.java.net/ajax/jsf-ajax/ (related to AJAX and request mapping/handling, not getting beans by name) – Konrad Garus Apr 15 '10 at 19:58

6 Answers6

264

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 @Injected @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:

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • 9
    You're second suggestion about just injecting the bean was so amazingly simple I had totally overlooked it. As always, your response is perfectly to the point. Thanks so much for your work here on SO. – jnt30 Sep 27 '11 at 18:43
  • 2
    In the meantime (speaking as of JSF 2.2) it seems like the method evaluateExpressionGet was extended with a third parameter that allows to specify the expected class so casting won't be necessary anymore. ``PostBean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", PostBean.class);`` – Marc Juchli Oct 08 '14 at 19:47
  • 1
    @Marc: Has been in from the beginning. Was just a leftover from a copypaste mistake I guess. Answer has been corrected. Thank you for notifying. – BalusC Oct 08 '14 at 19:48
  • `FacesContext` is available even though the `static` utility method `findBean()` is defined inside a plain Java class. How is it available there in a plain Java class which is not managed by JSF? – Tiny Jul 10 '15 at 01:07
  • 1
    @Tiny: it's in turn called by a JSF artifact within the same thread. – BalusC Jul 10 '15 at 04:55
  • Hi I get FacesContext context = FacesContext.getCurrentInstance(); context=null why?? and Trying to use HttpServletRequest request like this Bean bean = (Bean) request.getSession().getAttribute("ingresoSistema"); I got this: Servlet.service() for servlet servletsimple threw exception java.lang.IllegalStateException: Cannot create a session after the response has been committed. My bean: @ManagedBean(name = "ingresoSistema") @SessionScoped – Fernando Pie Jul 20 '16 at 16:06
  • @BalusC I was expecting `findBean(String beanName)` to be available in http://showcase.omnifaces.org/utils/Beans, but it's not. Is there any reason for that (other than keeping it strictly CDI)? – Jasper de Vries Apr 24 '17 at 15:38
  • @Jasper: You can use `Faces#evaluateExpressionGet()` for this. – BalusC Apr 28 '17 at 09:20
  • @BalusC OK, but you would still have to use `"#{" + beanName + "}"`, right? Or am I being lazy here? ;-) – Jasper de Vries May 18 '17 at 09:40
11

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.

John Yeary
  • 1,107
  • 20
  • 43
  • 3
    This is already covered by the currently accepted answer and even in a more convenient way (`Class` argument is namely unnecessary in this construct). – BalusC Dec 10 '12 at 18:55
3

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;
}
Subodh Joshi
  • 10,006
  • 23
  • 84
  • 177
Soujanya
  • 27
  • 1
3

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);
James P.
  • 17,929
  • 27
  • 89
  • 147
  • This probably won't work in a regular servlet. The FacesContext is a per-request thread-local artefact set up by the JSF lifecycle (usually the FacesServlet). – McDowell Apr 13 '10 at 22:14
  • 7
    ValueBinding is deprecated since JSF 1.2 over 4 years ago. – BalusC Apr 13 '10 at 22:51
  • @BalusC: It shows how up to date I am lol. On a sidenote, using a search engine to research techniques is turning out to be counterproductive with all the old information out there. @McDowell: That actually makes sense. I'll do a test just to see what happens. – James P. Apr 14 '10 at 00:01
0

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.

Anil
  • 327
  • 1
  • 10
-1

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.

ChRoNoN
  • 682
  • 7
  • 18