Spring UserDetailsService is not Serializable session attribute in google-apps-engine - java

Here we have a Spring based webapp in google apps engine.
I've created a UserDetailService class to load the UserDetails from the GAE data store (assuming this is the best approach).
#Service("springUserDetailsService")
public class SpringUserDetailsService implements UserDetailsService {
#Resource(name="userDao")
private IUserDao userDao;
//...
But GAE throws the following exception (apparently) when it tries to persist the session to the data store.
java.lang.RuntimeException: java.io.NotSerializableException: com.prepayproxy.servicelayer.SpringUserDetailsService
at com.google.apphosting.runtime.jetty.SessionManager.serialize(SessionManager.java:387)
at com.google.apphosting.runtime.jetty.SessionManager.createEntityForSession(SessionManager.java:364)
I first thought to Serialize the SprintUserDetailsService object, but it has a reference to my UserDao, which in turn has references to data source objects, at about that point I freaked out and decided to see if there's a better approach.

On your second point, I am only assuming that spring security is storing a reference to the UserDetailsService in the session, which is how it gets tied up with the GAE serialization of the session. All beyond my control as far as I see unless I missed something.
There's no reason for SpringSecurity to put a reference to your application's UserDetailsStore into the session. A UserDetailsStore is not conceptually session scoped.
If the session manager is trying to serialize a UserDetailsService, it is probably a result of a reference to the UserDetailsService in some other session scoped object.

Two options:
don't worry about the DataSource - spring, since version 3, serves a proxy which, when deserialized, gets a fresh data source, rather than the original (which is not relevant)
don't put your service in the session. Perhaps it is referenced by something that is in session scope, so make it volatile there.
See also this question

Related

Unable to deserialize Spring Session Scoped bean

I have the following session scoped bean:
#ManagedBean
#Component
#Scope(proxyMode= ScopedProxyMode.TARGET_CLASS, value="session")
public class SessionData implements Serializable {}
and I store tomcat sessions in a database. The problem is that, when the application tries to deserialize a stored session, I receive the following error:
org.apache.catalina.session.PersistentManagerBase.swapIn Error deserializing Session EE913D2ACAD49EB55EDA657A54DFA2CB: {1}
java.lang.ClassNotFoundException: de.myproject.SessionData$$EnhancerBySpringCGLIB$$768b59b9
It seems that it serialized actually the whole Spring context, and obviously there is no such class de.myproject.SessionData$$EnhancerBySpringCGLIB$$768b59b9 after server restarts, so I receive the aforementioned exception.
Is there a way to avoid this, so that the session-scoped bean is serialized properly?
UPDATE: There is an issue regards this which marked as resolved without comments, however I still face it.
Please have a try:
using: import org.springframework.test.util.AopTestUtils;
Serializable readyToSerialize = AopTestUtils.getUltimateTargetObject(yourInstance);
before serialize it.
Note: this code is usefull to understund the problem, if this work, you have to analyze the project architecture and dependecies, to better accomplish for production code. First of all, why you need to serialize a ScopedProxyMode.TARGET_CLASS
Having a bean with a scope session doesn't mean that the bean is serializable and that it can be stored in a session.
As you can guess from the name of the class, a proxy class is generated at runtime with a different name at each startup. This explains why a problem occurs at deserialization.
I guess you try to add this SessionData as an attribute of the web session. You should not. Store your POJO data in the web session without using beans.
If you use the bean to inject database connections or similar objects, forget it. You can just use session scope beans for particular contexts which don't feet your requirements I guess.
i don't know well the your task, but in my opinion a data object like this should not be a spring bean because spring bean should be business logic bean, controller bean and so on and not session dto.
for this reason i consider thag you should try to think why you want store the data of your spring bean, and try to decopled the data that you want in http session, #sessionattribute of springmvc,from the business logic bean that shoud nor be session aware.
i hooe that this can help you to change your implementation stategy in order to find the solution of your problem

JSF 2 Spring XRebel Huge session

I recently installed the XRebel plugin, which allows you to see current session size.
I discovered, that the session instantly gets to 10 mb on first page load(initialization of the auth session bean.).
To my setup:
I am using JSF 2.2, Spring 4 and Hibernate 4.
DAO Layer > Service Layer > Managed Bean
DAO Layer
#Named
#Singleton
#Repository
public class UserDao extends BaseDao<User>
{
...
}
Service Layer
#Service
#Named
#Singleton
public class UserService extends BaseService<User>
{
#Autowired
private UserDao dao;
...
}
My auth session bean, that gets loaded on first page load
#Named
#Component
#Scope("session")
public class Auth implements Serializable
{
#Autowired
private UserService userService;
...
}
In my applicationContext.xml I am using
<context:component-scan base-package="com.mypackage" />
This is a general issue I have when I autowire service beans in my session beans.
The Userservice only contains methods to retreive, save and delete user objects, there is no ArrayList containing users or anything else.
I have two #Autowired Services in my auth bean - UserService and SessionService.
If I commment out UserService, SessionService will reach the same size. If I comment out both there is a "DestructionCallbackBindingListener" from "org.springframework.web.context.request.ServletRequestAttribute..." that reaches 8mb instantly.
What am I doing wrong? How do I decrease the session size ?
I gladly accept any help.
Here is an image of XRebel showing that the userService takes about 8mb size in session. http://i.stack.imgur.com/TBXx3.png
Looking at XRebel, it seems that the beanFactory is saved in the user session.
I posted in the official forums regarding XRebel. This is the answer I received.
Indeed, the beanFactory is reachable from the session, through the
CGLIB proxy. We may need to improve to how we recognize objects that
are shared or should not be considered part of the session.
We try to show how much memory each session takes, but Spring
beanFactories are of course shared between sessions usually.
Often the fact that we filter out transient fields from the session
is enough, but we’ll take a look at the CGLIB/Spring proxies to see
how we can filter them out by a general rule or maybe we can just add
specific Spring classes to an ignore list.
In short: The beanfactory can be Ignored when looking at session size, optionally, if possible mark the autowired services transient.
Indeed you can ignore it mentally for now or if it’s possible then
yes, making the variables transient would exclude them.

JSF 2.0 manage a user

I am coming to Java from Rails and PHP, so my thinking here may be tainted.
I would like to implement a login system similar to ones I have done in my other systems (I understand you can manage login etc using the built in properties of Java EE, I just want to understand how I could do this manually and share objects amongst beans.)
With rails or php it is easy to maintain a session variable that holds the id of a logged in user. Then a global variable in PHP, or a property on the applicationController in rails can be pre-loaded with the user object, enabling it be available in all controllers/pages. That way the logged in status of the user and other parameters are easily accessible to all pages/controllers.
I don't know how to do a similar thing using JSF.
I know how to build a user object using JPA, and then create a managed bean with session scope that holds a reference to the user object after logging in using a loggin method from a login form. That part I understand:
#ManagedBean
#SessionScope
public class LogginController {
// inject persistence context, or use EJB to do actual loading etc
private User currentUser; //JPA Entity
void loginAction() {
// action from login form
// authenticates user and loads user object into currentUser property
Where I get stuck, is that although the managed bean that contains the currentUser property has session scope, how would I access that property in other managed beans to get the current user? Managed beans seem to exist in isolation from each other.
Is the following code acceptable?
#ManagedBean
public class SomeOtherBean {
#ManagedProperty
LoginController loginController;
public void someOtherMethod() {
User myUser = loginController.getCurrentUser();
//
// etc
Would the class having the bean injected also have to have SessionScope too?
Is this the wrong approach, would I need to manually set the session using the underlying ServletContext so that the user was accessible in other beans (i.e. save the id of the logged in user in the session, and then reload the user after accessing the user id session variable in different beans)?
Am I going about this all wrong? Is there an easier way I am missing.
Is the following code acceptable?
Yes (assuming that it's pseudo; in real code it should be a private property and you should specify the managed property value like so #ManagedProperty("#{loginController}") and provide at least a setter method).
Would the class having the bean injected also have to have SessionScope too?
Not necessarily. It can perfectly be a request or view scoped bean, but not an application scoped bean (it would result in an exception). At least, you should be very careful with choosing the bean scope. Do not choose a too broad scope for the data it holds. See also How to choose the right bean scope?.

How to dynamically manage multiple datasources

Similar topics have been covered in other threads, but I couldn't find a definitive solution to my problem.
What we're trying to achieve is to design a web app which is able to:
read a datasource configuration at startup (an XML file containing multiple datasource definitions, which is placed outside the WAR file and it's not the application-context or hibernate configuration file)
create a session factory for each one of them (considering that each datasource is a database with a different schema)
switch at runtime to different datasources based on user input (users can select which datasource they want to use)
provide the correct dao object to manage user requests.
At the moment we have a DAO Manager object which is able to read the datasource configuration file and instantiate multiple session factories, saving them in a map. Each session factory is created with a configuration containing the proper hibernate mapping classes (different for each database schema). Moreover we have multiple DAO interfaces with their implementations, used to access "their database".
At this point we would need a way to get from the DAO Manager a specific DAO object, containing the right session factory attached, all based on the user request (basically a call from the above service containing the datasource id or a custom datasource object).
Ideally the service layer should use the DAO Manager to get a DAO object based on the datasource id (for instance), without worrying about it's actual implementation: the DAO Manager would take care of it, by creating the correct DAO object and injecting in it the right session factory, based on the datasource id.
My questions are:
Is this a good approach to follow?
How can I use Spring to dynamically inject in the DAO Manager multiple DAO implementations for each DAO interface?
Once the session factories are created, is there a way to let Spring handle them, as I would normally do with dependency injection inside the application-context.xml?
Would the 2nd Level Cache still work for each Session Factory?
Is this a good approach to follow?
It's probably the only possible approach. So, yes.
How can I use Spring to dynamically
inject in the DAO Manager multiple DAO
implementations for each DAO
interface?
Dynamically? I thought you wanted to do it at startup time. If so, just provide an accessor with a list or array:
public void setMyDaos(List<Mydao> daos){
this.daos = daos;
}
Once the session factories are
created, is there a way to let Spring
handle them, as I would normally do
with dependency injection inside the
application-context.xml?
This one's tough. I'd say you will probably have to store your sessionFactory bean in scope=session

Spring session-scoped beans (controllers) and references to services, in terms of serialization

a standard case - you have a controller (#Controller) with #Scope("session").
classes put in the session usually are expected to implement Serializable so that they can be stored physically in case the server is restarted, for example
If the controller implements Serializable, this means all services (other spring beans) it is referring will also be serialized. They are often proxies, with references to transaction mangers, entity manager factories, etc.
It is not unlikely that some service, or even controller, hold a reference to the ApplicationContext, by implementing ApplicationContextAware, so this can effectively mean that the whole context is serialized. And given that it holds many connections - i.e. things that are not serializable by idea, it will be restored in corrupt state.
So far I've mostly ignored these issues. Recently I thought of declaring all my spring dependencies transient and getting them back in readResolve() by the static utility classes WebApplicationContextUtils and such that hold the request/ServletContext in a ThreadLocal. This is tedious, but it guarantees that, when the object is deserialized, its dependencies will be "up to date" with the current application context.
Is there any accepted practice for this, or any guidelines for serializing parts of the spring context.
Note that in JSF, managed beans (~controllers) are stateful (unlike action-based web frameworks). So perhaps my question stands more for JSF, than for spring-mvc.
In this presentation (around 1:14) the speaker says that this issue is resolved in spring 3.0 by providing a proxy of non-serializable beans, which obtains an instance from the current application context (on deserialization)
It appears that bounty didn't attract a single answer, so I'll document my limited understanding:
#Configuration
public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
MyService myService() {
return new MyService();
}
#Bean
#Scope("request")
public IndexBean indexBean() {
return new IndexBean();
}
#Bean
#Scope("request")
public DetailBean detailBean() {
return new DetailBean();
}
}
public class IndexBean implements Serializable {
#Inject MyService myService;
public void doSomething() {
myService.sayHello();
}
}
public class MyService {
public void sayHello() {
System.out.println("Hello World!");
}
}
Spring will then not inject the naked MyService into IndexBean, but a serializable proxy to it. (I tested that, and it worked).
However, the spring documentation writes:
You do not need to use the <aop:scoped-proxy/> in conjunction with beans that are scoped as singletons or prototypes. If you try to create a scoped proxy for a singleton bean, the BeanCreationException is raised.
At least when using java based configuration, the bean and its proxy can be instantiated just fine, i.e. no Exception is thrown. However, it looks like using scoped proxies to achieve serializability is not the intended use of such proxies. As such I fear Spring might fix that "bug" and prevent the creation of scoped proxies through Java based configuration, too.
Also, there is a limitation: The class name of the proxy is different after restart of the web application (because the class name of the proxy is based on the hashcode of the advice used to construct it, which in turn depends on the hashCode of an interceptor's class object. Class.hashCode does not override Object.hashCode, which is not stable across restarts). Therefore the serialized sessions can not be used by other VMs or across restarts.
I would expect to scope controllers as 'singleton', i.e. once per application, rather than in the session.
Session-scoping is typically used more for storing per-user information or per-user features.
Normally I just store the 'user' object in the session, and maybe some beans used for authentication or such. That's it.
Take a look at the spring docs for configuring some user data in session scope, using an aop proxy:
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection
Hope that helps
I recently combined JSF with Spring. I use RichFaces and the #KeepAlive feature, which serializes the JSF bean backing the page. There are two ways I have gotten this to work.
1) Use #Component("session") on the JSF backing bean
2) Get the bean from ELContext when ever you need it, something like this:
#SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName);
}
After trying all the different alternatives suggested all I had to do was add aop:scoped-proxy to my bean definition and it started working.
<bean id="securityService"
class="xxx.customer.engagement.service.impl.SecurityContextServiceImpl">
<aop:scoped-proxy/>
<property name="identityService" ref="identityService" />
</bean>
securityService is injected into my managedbean which is view scoped. This seems to work fine. According to spring documentation this is supposed to throw a BeanCreationException since securityService is a singleton. However this does not seems to happen and it works fine. Not sure whether this is a bug or what the side effects would be.
Serialization of Dynamic-Proxies works well, even between different JVMs, eg. as used for Session-Replication.
#Configuration public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.INTERFACES)
MyService myService() {
return new MyService();
}
.....
You just have to set the id of the ApplicationContext before the context is refreshed (see: org.springframework.beans.factory.support.DefaultListableBeanFactory.setSerializationId(String))
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// all other initialisation part ...
// before! refresh
ctx.setId("portal-lasg-appCtx-id");
// now refresh ..
ctx.refresh();
ctx.start();
Works fine on Spring-Version: 4.1.2.RELEASE

Categories

Resources