Skip to content

Service references in JSF session objects not restored when using persistent sessions [SPR-2675] #7364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Oct 4, 2006 · 7 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Oct 4, 2006

Oran Epelbaum opened SPR-2675 and commented

I am using JSF session-scoped backing beans, initialized by a WebApplicationContext using DelegatingVariableResolver. This all works great until Tomcat is restarted.
When Tomcat is restarted, or the app is re-deployed, Tomcat restores the session from the hard disk. This is a feature new to Tomcat 5.5, called "session persistence". BUT, for some reason the fields of the backing bean that are initialized with Spring are NOT restored, and remain null. As a result, NullPointerExceptions occur in my application after the restore.

As a workaround, we disable this Tomcat feature by adding the following to conf/context.xml:
<Manager pathname="">
<distributable />
</Manager>

I think this might be related to #6951 and #7214, but I'm not sure they relate to the same Tomcat version.


From my faces.xml:
<application>
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
<view-handler>org.apache.myfaces.tomahawk.application.jsp.JspTilesViewHandlerImpl</view-handler>
</application>

<managed-bean>
<managed-bean-name>myManagedBean</managed-bean-name>
<managed-bean-class>com.my.MyManagedBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>myService</property-name>
<value>#{myService}</value>
</managed-property>
</managed-bean>

From my web.xml:
<bean id="myService" class="com.my.MyServiceImpl" />

Note: MyServiceImpl is Serializable.


Affects: 2.0 final

Issue Links:

2 votes, 2 watchers

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

I frankly have no clue how Tomcat handles this. Does your MyManagedBean class mark the "myService" field as transient? Then this is what I would expect to happen. However, if it's not transient, Tomcat would have to serialize the content of the field, which is the Spring-managed service bean. This is all pretty much standard serialization, and I don't see anything we could do about this in Spring...

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Oran Epelbaum commented

Apparently your're right, the service is declared as transient, which definitely explains this behavior.
But there is actually a pretty good reason why it is declared as transient: the service internally has references to DAO objects extending HibernateDaoSupport, and HibernateDaoSupport is not Serializable. Therefore serialization wouldn't work anyway for these objects. These DAO references are of course built through the application context.

This seems to me to be a general problem: how to allow the web container to serialize session-state objects, which have references to non-serializable (but typically IoC-controlled) service and DAO objects?
A possible solution is to create Serializable wrapper beans, that wrap such non-Serializable beans, and delegate to them while implementing their interface. When serializing, such a wrapper bean would only store the reference ID of the wrapped bean, and when de-serializing it would look up the bean, using this reference, in the application context.

I think we may resort to building such a wrapper objects specifically for our services as a fix to this problem, but this is something that's calling for a generic IoC solution: some kind of factory that would create such a wrapper bean on the fly for any object, in the application context.

What do you think?

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Well, this is the same general issue as with all session-scoped service objects then: If they contain references to shared service objects, those either have to marked as transient (losing those references on serialization) or not considered serializable in the first place (the entire object failing on serialization). This is not really JSF-specific; it's the same with any kind of session object in a Servlet environment.

However, a general solution is not apparent here. Spring has no way of interfering in the Servlet container's session persistence process: This means that the Servlet container will simply deserialize those instances and expose them in the reactivated session. We cannot perform dependency injection there, simply because the lifecycle of those objects is beyond Spring's control.

So I'm afraid there are only two options:

  1. Rearchitect your session-scoped objects to only hold state (as dumb data holders), with your services just operating on them rather than service references residing in the session objects themselves.
  2. Turn off any kind of session persistence, which you of course can only do if you're not actually relying on session persistence in the first place (many applications don't really need this).

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Oran Epelbaum commented

I'll go for option 2 for now, but it feels wrong having to choose between two such options. This looks like a general issue that requires a general solution - web applications would be much better off not being sensitive to serialization / de-serialization of their web-tier beans by the web container.

In my comment above I outlined a general solution, and I think it makes sense for this to be part of Spring. When Spring IoC controls a bean, it can certainly wrap it so that it appears to be Serializable. "Forcing" a bean to act as Serializable, while in fact its lifecycle is actually managed by the application context, seems like a cool feature, for avoiding having to choose between those two gloomy options.

To explain the idea a bit further, if you have a MyService interface with a void method named method(), I'm suggesting to create a Spring IoC factory that would wrap it with the dynamic equivalent of:

class StaticWrapper implements ApplicationContextAware, MyService, Serializable {
private String internalBeanRef; // + getter and setter
private transient MyService internal; // + getter and setter
private transient ApplicationContext applicationContext; // + getter and setter
public void myMethod() {
lazyInit();
internal.myMethod();
}
synchronized private void lazyInit() {
if(internal!=null || internalRefBean==null) return;
internal = (MyService) applicationContext.getBean(internalRefBean);
}
}

The only problem i see here is initializing the application context member, since it's not Serializable. Maybe some static global variable is required for storing application context references for this purpose - this is just a sketch.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Thanks for the suggestion - I do see the general idea.

You pointed out the most important issue already: Which ApplicationContext do you use for reobtaining the service objects? Spring's philosophy is very much based on avoiding static state wherever possible, hence we refrain from storing ApplicationContexts in static variables unless absolutely necessary. We only do it for two purposes at present: for holding a shared ApplicationContext in an EJB tier, and for holding the ApplicationContext's that exposed for Spring 2.0's @Configurable support. I guess we can consider offering something like this for session persistence in a web application, which is why I turned this issue into an enhancement request already.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Oran Epelbaum commented

Well this could be number 3 :-)
Thanks and kudos for the quick response.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented May 6, 2009

Juergen Hoeller commented

This is finally making its way into Spring now! See my comment on #6812...

Juergen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants