I'm probably too blind and too new to OmniFaces, and could not find a basic method in the API to retrieve a backing bean instance. Where can I find such a method if there is one? Like this one:
public static Object getBackingBean(String name) {
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ValueExpression expression = app.getExpressionFactory()
.createValueExpression(context.getELContext(), String.format("#{%s}", name), Object.class);
return expression.getValue(context.getELContext());
}
Or a more dynamic version with generics:
public static <T> T getBackingBean(String name) {
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ValueExpression expression = app.getExpressionFactory()
.createValueExpression(context.getELContext(), String.format("#{%s}", name), Object.class);
return (T) expression.getValue(context.getELContext());
}
We have a method that's nearly like that, but it can evaluate (and get) any kind of expression not just a simplified root expression.
It's Faces.evaluateExpressionGet.
You use it as follows:
MyBean myBean = Faces.evaluateExpressionGet("#{myBean}");
With MyBean being e.g. defined as follows:
#ViewScoped
#ManagedBean
public class MyBean {
// ...
}
Related
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.
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:
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.
I have composite component:
<my:component value="#{bean.property1.property2}/>
From composite component I need to get class of bean.property1 to read its annotations.
I do it by the following code:
ValueExpression valueExpression = expressionFactory.createValueExpression(FacesContext.getCurrentInstance().getELContext(),
"#{bean.property1}", Object.class);
Object bean = valueExpression.getValue(FacesContext.getCurrentInstance().getELContext());
Class<?> beanClass = bean.getClass();
This works well but if I use my:component from a facelet and pass bean as a parameter via ui:param this does not work because bean can't be resolved.
Probably I should use FaceletContext as ELContext instead of FacesContext.getCurrentInstance().getELContext():
FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes()
.get("javax.faces.FACELET_CONTEXT");
But this doesn't work on RENDER_RESPONSE phase (from encodeBegin method). It returns last used ELContext instead of actual context (I am not surprised :) ).
The goal is to get class of #{bean.property1} from my:component. How can I do it?
This is easy with RichFaces:
ValueExpressionAnalayser analyser = new ValueExpressionAnalayserImpl();
ValueDescriptor valueDescriptor = analyser.getPropertyDescriptor(context, valueExpression);
Class<?> beanClass = valueDescriptor.getBeanType();
This is ok for me.
Also there is ValueExpressionAnalayzer in javax.faces.validator package but it is package private and can't be used.
You could pass the bean as a parameter to the component.
1) Declare the attribute in the component interface file(if you are using composite component):
<cc:interface componentType="myComponentClass">
<cc:attribute name="myBean" preferred="true"/>
..others attributes
<cc:interface>
2) Implement the respective getter and setter for "myBean" attribute in the component class(myComponentClass)
protected enum PropertyKeys {
myBean;
String toString;
PropertyKeys(String toString) {
this.toString = toString;
}
PropertyKeys() {}
#Override
public String toString() {
return ((this.toString != null) ? this.toString : super.toString());
}
}
public YourBeanClass getMyBean() {
return (YourBeanClass) getStateHelper().eval(PropertyKeys.myBean, null);
}
public void setMyBean(YourBeanClass myBean) {
getStateHelper().put(PropertyKeys.myBean, myBean);
}
3) Set the attribute on you jsf page:
<my:component myBean="#{bean}"/>
4) In the component's render class cast the UIComponent to myComponentClass.
#Override
public void encodeBegin(FacesContext pContext, UIComponent pComponent)
throws IOException {
myComponentClass myComponent = (myComponentClass) pComponent;
myComponent.getYourAttribute();
}
I'm using a custom annotation security as described in this link. I'm upgrading my jsf managed beans from #ManagedBean to #Named (CDI). Since the CDI does not support the scope #ViewScoped, i'm using org.omnifaces.cdi.ViewScoped. However, in this case, this check fails if method.isAnnotationPresent(Permissao.class){}. How should I adapt my security check to use with CDI + ViewScoped from Omnifaces?
Edit
Using #ManagedBean/ViewScoped(jsf) instead of #Named/ViewScoped(cdi + omnifaces) works.
The problem occurs in this line if (metodo.isAnnotationPresent(Permissao.class)) {}
public void verificaPermissaoAcesso(ActionEvent event) {
final FacesContext facesContext = FacesContext.getCurrentInstance();
UIComponent source = event.getComponent();
ActionSource2 actionSource = (ActionSource2) source;
MethodExpression methodExpression = actionSource.getActionExpression();
String expressao = methodExpression.getExpressionString(); // #{nomeManagedBean.nomeMetodo(param)}
String nomeManagedBean = expressao.substring(0, expressao.indexOf('.')).substring(2);
String nomeMetodoComParenteses = expressao.substring(expressao.indexOf('.') + 1);
String nomeMetodo = nomeMetodoComParenteses.substring(0, nomeMetodoComParenteses.indexOf("("));
ELContext elContext = facesContext.getELContext();
ExpressionFactory factory = facesContext.getApplication().getExpressionFactory();
ValueExpression ve = factory.createValueExpression(elContext, "#{" + nomeManagedBean + '}', Object.class);
//Object jsfManagedBean = ve.getValue(elContext);
Context ctx = bm.getContext(org.omnifaces.cdi.ViewScoped.class);
Bean bean = bm.resolve(bm.getBeans(nomeManagedBean));
Object jsfManagedBeanProxy = ctx.get(bean);
List<Method> listaMetodos = Arrays.asList(jsfManagedBeanProxy.getClass().getMethods());
for (Method metodo : listaMetodos) {
if (nomeMetodo.equals(metodo.getName())) {
if (metodo.isAnnotationPresent(Permissao.class)) {
Permissao anotacaoSeguranca = metodo.getAnnotation(Permissao.class);
SegurancaUtil.verificar(anotacaoSeguranca.acoes());
break;
}
}
}
}
My annotation class
#Documented
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Permissao {
String[] acoes();
}
My annotated method in jsf managed bean
#Permissao(acoes={"permission1", "permission2"})
public void myMethod(long id) {}
Edit 2 - Solution by #meriton
Context ctx = bm.getContext(org.omnifaces.cdi.ViewScoped.class);
Bean bean = bm.resolve(bm.getBeans(nomeManagedBean));
Object jsfManagedBeanProxy = ctx.get(bean);
CDI doesn't inject a naked CDI bean as a dependency, but a proxy that redirects to the contextual object of the active scope. This proxy class does not have your annotation.
See https://issues.jboss.org/browse/CDI-10 for how to unwrap the proxy.
This question already has answers here:
Get JSF managed bean by name in any Servlet related class
(6 answers)
Closed 7 years ago.
I need to know what's the best method for accessing a JSF managedBean (which is defined having application scope) from a servlet.
Currently I have something like this in my servlet:
MyApplicationScopeBean bean = null;
try {
FacesContext fContext = FacesUtil.getFacesContext(req, resp);
ServletContext sc = (ServletContext) fContext.getExternalContext().getContext();
bean = (MyApplicationScopeBean) sc.getAttribute("myManagedBean");
} catch (Exception e) {
e.printStackTrace();
}
FacesUtil.java (as described in http://balusc.blogspot.com/2006/06/communication-in-jsf.html):
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FacesUtil {
// Getters -----------------------------------------------------------------------------------
public static FacesContext getFacesContext(
HttpServletRequest request, HttpServletResponse response)
{
// Get current FacesContext.
FacesContext facesContext = FacesContext.getCurrentInstance();
// Check current FacesContext.
if (facesContext == null) {
// Create new Lifecycle.
LifecycleFactory lifecycleFactory = (LifecycleFactory)
FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
// Create new FacesContext.
FacesContextFactory contextFactory = (FacesContextFactory)
FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
facesContext = contextFactory.getFacesContext(
request.getSession().getServletContext(), request, response, lifecycle);
// Create new View.
UIViewRoot view = facesContext.getApplication().getViewHandler().createView(
facesContext, "");
facesContext.setViewRoot(view);
// Set current FacesContext.
FacesContextWrapper.setCurrentInstance(facesContext);
}
return facesContext;
}
// Helpers -----------------------------------------------------------------------------------
// Wrap the protected FacesContext.setCurrentInstance() in a inner class.
private static abstract class FacesContextWrapper extends FacesContext {
protected static void setCurrentInstance(FacesContext facesContext) {
FacesContext.setCurrentInstance(facesContext);
}
}
}
I always get a null when trying to access the bean from the servlet. What are your suggestions?
I'm running JSF 1.2 on Tomcat 6
Thanks for your help.
JSF stores application scoped managed beans just in the ServletContext. In servlets, the ServletContext is just available by the inherited getServletContext() method. You don't need to manually create a whole FacesContext around it. That's only an unnecessarily expensive task for this purpose.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Bean bean = (Bean) getServletContext().getAttribute("bean");
// ...
}
If it returns null, then it simply means that JSF hasn't kicked in yet to auto-create the bean for you (i.e. the servlet is called too early). You would then need to create and store it yourself. It will be used by JSF if the managed bean name (the attribute key) is the same.
if (bean == null) {
bean = new Bean();
getServletContext().setAttribute("bean", bean);
}
That said, what's the purpose of this servlet? Aren't you trying to achieve some functional requirement the wrong way?
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.
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:
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.