Accessing #SessionCoped #Named beans from a HttpSession [duplicate] - jsf-2.2

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.

Related

DelegatingDataSource Spring boot

I am trying to implement Spring Boot AOP for data-source pointcut - where before running any query I need to set client context in DB connection.
I was trying this approach of using DelegatingDataSource. But I am getting below error during server startup
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
Please let me know DeletegatingDatasource for JNDI based DB lookup.
Edit 1: AOP - I tried to add pointcut execution(public * javax.sql.DataSource+.getConnection(..)). This works only when Spring datasource is used with username/password. Once i deploy in Jboss with JNDI I am getting WildFlyDataSource Proxy error. So, instead of AOP approach I thought of using DelegatingDatasource
// AOP Example
#Pointcut("execution(public * javax.sql.DataSource+.getConnection(..))")
void prepareConnectionPointcut() {
logger.debug("prepareConnectionPointcut");
}
#AfterReturning(pointcut = "prepareConnectionPointcut()", returning = "connection")
void afterPrepareConnection(Connection connection) {
// Set context in Connection - return same connection for query execution
}
But when i deploy this code in JBoss - I am getting WildFlyDataSource datasource bean creation error.
Error creating bean with name
'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration':
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'dataSource' defined in class path resource
[org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.class]:
Initialization of bean failed; nested exception is
org.springframework.aop.framework.AopConfigException: Could not
generate CGLIB subclass of class
org.jboss.as.connector.subsystems.datasources.WildFlyDataSource:
Common causes of this problem include using a final class or a
non-visible class; nested exception is
org.springframework.cglib.core.CodeGenerationException:
java.lang.NoClassDefFoundError-->org/jboss/as/connector/subsystems/datasources/WildFlyDataSource
I have also added proxyTargetClass flag during initialization
#EnableAspectJAutoProxy(proxyTargetClass = true)
Thanks #M.Deinum for recommendation of using BeanPostProcessor & Implement DelegatingDatasource for setting client info. Please find snippet below which i have implemented to accomplish this in Spring Boot which works well with JBoos JNDI based connection or Spring Boot URL Datasource connection.
#Component
public class MyBeanPostProcessor implements BeanPostProcessor {
private static Logger logger = LoggerFactory.getLogger(MyBeanPostProcessor.class);
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource) {
// Check DataSource bean initialization & enclose it with DelegatingDataSource
logger.debug("MyBeanPostProcessor:: postProcessAfterInitialization:: DataSource");
DataSource beanDs = (DataSource) bean;
return new MyDelegateDS(beanDs);
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource) {
logger.debug("MyBeanPostProcessor:: postProcessBeforeInitialization:: DataSource");
}
logger.debug("MyBeanPostProcessor:: postProcessBeforeInitialization:: " + beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
}
My implementation of DelegatingDataSource to handle each user request to set client context in DB connection session
public class MyDelegateDS extends DelegatingDataSource {
private static Logger logger = LoggerFactory.getLogger(MyDelegateDS.class);
public MyDelegateDS(DataSource delegate) {
super(delegate);
logger.debug("MyDelegateDS:: constructor");
}
#Override
public Connection getConnection() throws SQLException {
logger.debug("MyDelegateDS:: getConnection");
// To do this context only for user Request - to avoid this during Server initialization
if (RequestContextHolder.getRequestAttributes() != null
&& ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest() != null) {
logger.debug("MyDelegateDS:: getConnection: valid user request");
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
// Checking each user request & calling SP to set client context before invoking actual native query/SP
}
logger.debug("MyDelegateDS:: getConnection: Not User Request");
return super.getConnection();
}
}
Hope this is helpful for someone facing same problem

Spring Create Prototype Bean on demand and reference the bean created later

I am newbie to spring and I am trying to modify my app to implement spring framework.
My request is to create a new bean for every new request and then refer that bean later in the code, for setting the values to it from a singleton bean.
I am trying to declare the bean as prototype and refer that bean in my singleton bean using lookup method.
But my problem was when trying to get the created prototype bean later for setting the values, I see its creating new bean again when getting the bean.
#Component
public class PersonTransaction {
#Autowired
PersonContext btContext;
#Autowired
PersonMapper personMapper;
public void setPersonMapper(PersonViewMapper personMapper) {
this.personMapper = personMapper;
}
public PersonBTContext createContext() throws ContextException {
return btContext = getInitializedPersonBTInstance();
}
private PersonBTContext getContext() throws ContextException{
return this.btContext;
}
public void populateView(UserProfileBean userProfile) throws ContextException {
personMapper.populateView(userProfile,getContext());
}
#Lookup(value="personContext")
public PersonBTContext getInitializedPersonBTInstance(){
return null;
}
}
below is my prototype class
#Component("personContext")
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PersonContext extends ReporterAdapterContext {
private List<Person> persons = null;
private Person person = null;
private List<String> attributes = null;
private boolean multiplePersons = false;
private boolean attributeSelected = false;
public boolean isMultiple() {
return multiplePersons;
}
public boolean isAttributeSelected() {
return attributeSelected;
}
private void setAttributeSelected(boolean attributeSelected) {
this.attributeSelected = attributeSelected;
}
// remaining getters/setters
}
when i call createContext from singleton PersonTransaction class, it should create new prototype bean and how can get the created prototype bean later by calling getContext() method (what i am doing by this.btContext is returning new bean again, I guess !!)..
Need help in getting the created prototype bean later for setting the values.
appreciate ur help..
You want to create a request scoped bean, not a prototype scoped bean. Take a look at Quick Guide to Spring Bean Scopes which describes different bean scopes, including the request scope:
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public PersonContext personContext() {
return new PersonContext();
}
This should simplify your logic as long as you can discard the bean after the request is processed.

I cannot keep the bean stateful when the spring bean is value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS

here is the spring bean:
#Repository
#Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TestBean {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
and here is the very simple codes to access the bean:
TestBean testBean = (TestBean) SpringContext.getBean("testBean");//#1
testBean.setText("aaaaa"); //#2
System.out.println(testBean.getText()); //#3
and the result is that testBean.getText() is null.
When i try to debug the codes, i found that the instance of testBean in #2 is not the same instance as that in #3. for example:
#2: TestBean#988995e
#3: TestBean#69bf7e71
Any help? Thanks!
SpringContext.getBean("testBean") returns the Proxy object for you. And any method invocation is delegates to the DynamicAdvisedInterceptor. Which, in turn, does target = getTarget(); to generate CglibMethodInvocation. And the magic is hidden in that getTarget(), which is SimpleBeanTargetSource for the prototype beans and has a code:
public Object getTarget() throws Exception {
return getBeanFactory().getBean(getTargetBeanName());
}
So, any method invocation on the TestBean asks BeanFactory for the new instance of that class. That's why your setText("aaaaa") isn't visible for testBean.getText(), because each method is for its TestBean object, not the same.
Such prototype objects can't be changed from the code manually. They are managed by ApplicationContext and only the last one can populate their internal state. From the code you can only read them.
And if your TestBean is populated with the same values you will get the same from the testBean.getText(), but all those call will be done for different objects.

Spring bean definition - get bean class

I'm trying the get Bean class name without initialize the bean.
I need to know the class , I could get the bean from applicationContext and to check the class name from the bean instance, But I want to know the class with out actually creating/init the bean..
Is it possible ?
Object bean = applicationContext.getBean("beanName");
bean.getClass();
You can't do this after creating the ApplicationContext. Most ApplicationContext implementations will refresh() themselves and force instantiation of the beans.
What you can do is create a BeanFactoryPostProcessor in which you get the target bean definition and check the bean class.
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String className = beanFactory.getBeanDefinition("").getBeanClassName();
}
But note, as the javadoc for getBeanClassName() states
Hence, do not consider this to be the definitive bean type at runtime
but rather only use it for parsing purposes at the individual bean
definition level.
So use it with a grain of salt.
If you give us more details as to what you are trying to accomplish, there might be alternatives.
The code provided by Sotirious will not work for the beans that have parent beans and for the beans that are defined using Java Config or using #Component annotation (and similar annotatios like #Service, #Repository, #Component).
Just an extension which checks if it is AnnotatedBeanDefinition or if the bean has a parent:
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
String beanClassName = getBeanClassName(beanDefinitionName, beanFactory);
}
}
private String getBeanClassName(String beanName, ConfigurableListableBeanFactory beanFactory) {
String beanClassName;
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition instanceof AnnotatedBeanDefinition) {
AnnotationMetadata metadata = ((AnnotatedBeanDefinition) beanDefinition).getMetadata();
beanClassName = metadata.getClassName();
} else {
beanClassName = beanDefinition.getBeanClassName();
while (beanClassName == null) {
BeanDefinition parentBeanDefinition = beanFactory.getBeanDefinition(beanDefinition.getParentName());
beanClassName = parentBeanDefinition.getBeanClassName();
beanDefinition = parentBeanDefinition;
}
}
return beanClassName;
}
Note, this approach will not work in the case factory method is used. As Java Doc says:
Also, this may just be the class that a factory method is called on, or it may even be empty in case of a factory bean reference that a method is called on. Hence, do not consider this to be the definitive bean type at runtime but rather only use it for parsing purposes at the individual bean definition level.

Managed beans with custom ViewScope

I'm doing a Web application using Spring 3.1.0.RELEASE, JSF 2.x, JPA 2 with Hibernate Provider. I use PrettyFaces 3.3.2 for friendly URL. The application run on Tomcat 6.35 .
I wanted to use the Jsf ViewScope so I decided to follow the implementation found on the web : http://comdynamics.net/blog/109/spring3-jsf2-view-scope/
public class ViewScope implements Scope {
private static final Logger logger = LoggerFactory.getLogger(ViewScope.class);
#Override
public Object get(String name, ObjectFactory objectFactory) {
final Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
Object instance = viewMap.get(name);
if (instance == null) {
instance = objectFactory.getObject();
viewMap.put(name, instance);
}
return instance;
}
#Override
public Object remove(String name) {
logger.debug("ViewScope::remove {}", name);
return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
}
#Override
public String getConversationId() {
return null;
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
//Not supported
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
}
I notice that #PreDestroy are not called on them like show this question #PreDestroy never called on #ViewScoped.
Does it mean that the Managed beans with ViewScope are never destruct ? Which conduct to memory leak. Should we use this scope so?
It's only happen with custom Viewscope on Spring or also on Mojarra ?
Thanks.
Problem is incorrect implementaiton of view scope. It is creates Spring bean objectFactory.getObject(); but never destroy it.
To solve it - check correct implementation with support for registerDestructionCallback.
BWT, current Mojjara implementation will not call #PreDestory on your bean too.
But it will free bean instance at least.
I tried the work around for Jsf view scope bean memory leaks using spring custom view scope. It works for both Jsf 2.1 & 2.2.Try the code in below link.
Memory leak with ViewScoped bean?

Resources