<% HttpSession sess = rquest.getSession(); FooBean foo = (FooBean)sess.getAttribute("fooBean"); foo.someMethod(); %>And the jsf file has the following:
<ice:form onsubmit="#{fooBean.doAction}">Here the tag ice is used because it is using icefaces. The name fooBean is for a Spring bean defined in applicationContext.xml as below:
<bean id="fooBean" class="FooBean" scope="session"> <constructor-arg><ref bean="x" /> <constructor-arg> <constructor-arg><ref bean="y" /> <constructor-arg> </bean> <bean id="x" class="X"/> <bean id="y" class="Y" scope="session"/>And in the faces-config.xml, there is the following:
<faces-config> <application> <variable-resolver> org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver> </application> </faces-config>
The application is accessed by app/a.faces. And then you can access the jsp file app/b.jsp without any problem. But if you access the application using app/b.jsp as the first step, it will give NullPointerException when calling foo.someMethod() because foo is null.
The tricky thing here is how the "fooBean" is put into the session as an attribute. The answer is in the Spring DelegatingVariableResolver class and DefaultListableBeanFactory class.
When user types app/a.faces, the resolver sees #{fooBean.doAction}. It checks the applicationContext.xml and finds the bean definition. So it creates the bean x, y, and then fooBean. The bean x is a singleton. It is already created at the application startup. So the resolver only needs to get the cached instance of x. But the bean y has a scope of session. So the resolver calls DefaultListableBeanFactory and creates a brand new instance of y. And it puts it as an attribute into the HTTP Session object. After both x and y are created, a new fooBean is created and put into the session as an attribute since its scope is also session. So these session beans are created lazily when there are referenced.
Now if you access app/b.jsp without firstly accessing app/a.faces, the Spring resolver is not invoked. The session object has no attribute named "fooBean". And you will get a null object for this attribute.
The following is the method stacks showing the Spring bean is resolved and set into the HTTP session as an attribute.
owns: InterceptingServletSession (id=15648) MyAttributeListener.attributeAdded(HttpSessionBindingEvent) line: 13 EventsManager.notifySessionAttributeChange(HttpSession, String, Object, Object) line: 302 MemorySessionContext(SessionContext).notifySessionAttributeChange(HttpSession, String, Object, Object) line: 1479 MemorySessionData(SessionData).setAttribute(String, Object, boolean) line: 1121 MemorySessionData(SessionData).setAttribute(String, Object) line: 959 InterceptingServletSession(ProxyHttpSession).setAttribute(String, Object) line: 107 ServletSessionAttributeMap.setAttribute(String, Object) line: 20 ServletSessionAttributeMap(AbstractAttributeMap).put(Object, Object) line: 157 FacesRequestAttributes.setAttribute(String, Object, int) line: 108 SessionScope(AbstractRequestAttributesScope).get(String, ObjectFactory) line: 44 SessionScope.get(String, ObjectFactory) line: 90 DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class, Object[], boolean) line: 298 DefaultListableBeanFactory(AbstractBeanFactory).getBean(String, Class, Object[]) line: 185 DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 164 XmlWebApplicationContext(AbstractApplicationContext).getBean(String) line: 881 DelegatingVariableResolver.resolveSpringBean(FacesContext, String) line: 136 DelegatingVariableResolver.resolveVariable(FacesContext, String) line: 109 NamedValue.evaluate(ExpressionInfo) line: 145 ComplexValue.evaluate(ExpressionInfo) line: 166 ExpressionEvaluatorImpl.evaluate(ExpressionInfo) line: 263 ValueBindingImpl.getValue(FacesContext, String) line: 160 ValueBindingImpl.getValue(FacesContext) line: 143 HtmlForm(HtmlForm).getOnsubmit() line: 501
No comments:
Post a Comment