JSF 2.0 Injecting is controlled by a bean with a different scope

I have a controller that is stateless which handles forms processing. This is defined as ApplicationScoped . On my page, I have a form related to bean support defined as ViewScoped .

The error I received when I want to process the form:

 serverError: class com.sun.faces.mgbean.ManagedBeanCreationException Unable to create managed bean myController. The following problems were found: - The scope of the object referenced by expression #{myFormBean}, view, is shorter than the referring managed beans (myController) scope of application 

In my form:

  Name: <h:inputText value="#{myFormBean.name}" id="name" /> <h:commandButton value="Save Name" action="#{myController.processForm}"> <f:ajax render="nameResult" /> </h:commandButton> Your name is <h:outputText value="#{myFormBean.name}" id="nameResult"/> 

Controller:

 @ManagedBean @ApplicationScoped public class MyController { @ManagedProperty("#{myFormBean}") private MyFormBean myBean; public void processForm() { System.out.println(myBean.getName()); // Save current name in session FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put( "name", myBean.getName()); } } 

Bean support:

 @ManagedBean @ViewScoped public class MyFormBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } 

I could solve this by setting the controller as SessionScoped, but this is not a clean path, as the controller has no status, so I do not need one controller for each session. One controller for the entire application should be sufficient.

I have Spring MVC background, that's why I got confused about how to do something with JSF 2.0

+4
source share
2 answers

There is a flaw in your design. Your controller is not stateless at all. It has a property that is different for each request / view, namely myBean . If it was supported, then each new request / view will override the previously installed one, and enduser will encounter the property value of a completely different end user. This leads to problems in high parallel situations.

You need to make the / view request an area, not an application area. However, I believe that you should approach it in a completely different way. You manually set the attribute in the session area in the action method, and do not set it as a property of a (nested) session limited by a bean. How to solve it correctly depends on the functional requirement, which is not clear from the question.

+11
source

I have JSF Managed Beans with different areas that reference each other, and I found that Spring adequately meets my needs. The key to success was AOP Spring, which will maximize bean links and give me more flexible auto-increment. I think it would be wise to mix JSF and Spring in a similar way to achieving your goals.

I do not use JSF scope declaration annotations to declare my beans. Instead, I use Spring to declare my beans, assign them scopes, and indicate that I want the Beans to have weird proxies generated for them (so that they can automatically get outsourced when they are referenced). I use Spring el-resolver to make my Spring Beans addressable as JSF2 managed Beans in EL.

I do not use the presentation area in my program, I use the Beans-bound session area with the request, referring to them. But, I suspect that my approach might be tailored to your Beans view.

I do not use annotations to declare my beans, I use XML to declare my Beans and their areas. I just feel comfortable having all my bean ads cataloged in one place. I am sure that there is a clean, annotation-based approach to achieve what I have. I use the @Autowired annotation in Beans to indicate where links to other Beans should be linked. This shortens my XML configuration, eliminates the need for getter / seters, and gives me a bit more Java side than I could get from pure XML.

Finally, I gave myself the usual "SmartSession" area. This is essentially the same as the session area, except that it is automatically auto-incremented every time a bean is logged out of the session (this protects against bean replicas that are not in the cluster in the scenario of switching to another resource.)

I came to the conclusion that for the session (and I assume the view), for Beans to work, you need to make the bean Serializable and mark any @Autowired fields as temporary. SmartSession gives me confidence in this context, to be sure that I remain auto-informed even in exceptional cases. I based the idea of ​​SmartSession for the user area: Initialize already created objects in Spring , as well as Internet sources in order to write user areas.

Here are some code snippets that I hope will give you some ideas -

Sample bean session:

 public class UserProfileContainer implements Serializable { private static final long serialVersionUID = -6765013004669200867L; private User userProfile; public void setUserProfile(User userProfile) { this.userProfile = userProfile; } public User getUserProfile() { return this.userProfile; } } 

The bean that references my bean class:

 public class KidProfileEditor implements Serializable { private static final long serialVersionUID = 1552049926125644314L; private String screenName; private String password; private String confirmPassword; private String firstName; private String lastName; private String city; private String state; private String notes; private String country; @Autowired private transient UserProfileContainer userProfileContainer; } 

Snippet from my application Context.xml:

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:util="http://www.springframework.org/schema/util" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:jms="http://www.springframework.org/schema/jms" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-lazy-init="true" > <!-- BOILERPLATE magic AOP setup tags --> <context:annotation-config /> <context:component-scan base-package="com.woldrich.kidcompy" /> <aop:aspectj-autoproxy /> <!-- JSF2+Spring custom scope configurations --> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="safetySession"> <bean class="com.woldrich.kidcompy.faces.util.SpringSafetySessionScope"/> </entry> </map> </property> </bean> <bean id="userProfileContainer" class="com.woldrich.kidcompy.auth.UserProfileContainer" scope="safetySession"> <aop:scoped-proxy /> </bean> <bean id="kidProfileEditor" class="com.woldrich.kidcompy.faces.actionview.KidProfileEditor" scope="request" /> </beans> 

snippet web.xml:

 <web-app xsi:schemaLocation="http://java.sun.com/xml/ns/javaee /WEB-INF/includes/schema/web-app_2_5.xsd" id="KidCompy" version="2.5" metadata-complete="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"> <distributable/> <context-param> <description>Allows the Spring Context to load multiple application context files</description> <param-name>contextConfigLocation</param-name> <param-value>classpath:/mainApplicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> </web-app> 

faces-config.xml snippet:

 <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee /WEB-INF/includes/schema/web-facesconfig_2_0.xsd" version="2.0"> <application> <el-resolver> org.springframework.web.jsf.el.SpringBeanFacesELResolver </el-resolver> </application> </faces-config> 
+2
source

All Articles