Description
When using Spring Session with scoped Beans (i.e. request / session / etc), the following error can occur:
Cannot deserialize BeanFactory with id application:9000: no factory registered for this id
This means that using Spring Session and Spring Security OAuth (which uses session and request scoped beans) can fail. The failure happens when DefaultListableBeanFactory.serializationId
has a different value from when the serialization takes place and when the deserialization takes place. There are a few places in which this is might happen.
Boot Applications
NOTE This is tracked at spring-projects/spring-boot#5265
In a Spring Boot application the ContextIdApplicationContextInitializer sets AbstractApplicationContext.id. Then in GenericApplicationContext.refreshBeanFactory() the id is set as the DefaultListableBeanFactory.serializationId
.
Unfortunately Spring Boot's ContextIdApplicationContextInitializer.getApplicationId derives the name of the id from the name of the application and the port the application is running on. This means if you have the same Spring Boot application running on different ports, Session Scoped beans will not work across between the two instances of the application.
This can be worked around by setting the application name and application index using something like this:
spring.application.name=application
spring.application.index=1
Unfortunately, this impacts other places where the application name and index are used to determine which instance of Spring Boot is being used.
Spring Cloud
NOTE This is tracked at spring-cloud/spring-cloud-commons#93
In Spring Cloud, the GenericScope.setSerializationId sets the serialization id. This means both RefreshScope
and ThreadScope
(which inherit from GenericScope
) are impacted by this.
The default value is a UUID calculated from the bytes of the Spring Bean names. Unfortunately the calculation of the resulting id does not appear to be constant. When the same application is restarted, the UUID is still different than the previous id.
This can be worked around by creating a RefreshScope
bean definition. For example:
@Bean
public static RefreshScope refreshScope() {
RefreshScope refresh = new RefreshScope();
refresh.setId("application:1");
return refresh;
}
Examples
You can find an example for reproducing this in rwinch/tut-spring-security-and-angular-js. Use the following instructions:
- Ensure all cookies for localhost are cleared out
- Start up Redis instance
- open http://localhost:8080/
- Authenticated with user / password
Use the following branches
- See serialization issues spring-session-395
- Fix serialization issues with workarounds spring-session-395-fixes
- Remove OAuth from resource server oauth-session
Full Stacktrace
A full stacktrace can be found below:
2016-02-26 14:51:34.092 ERROR 51427 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.lang.IllegalStateException: Cannot deserialize BeanFactory with id application:9000: no factory registered for this id
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:41) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:316) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
at org.springframework.data.redis.core.AbstractOperations.deserializeHashMap(AbstractOperations.java:277) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
at org.springframework.data.redis.core.DefaultHashOperations.entries(DefaultHashOperations.java:227) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
at org.springframework.data.redis.core.DefaultBoundHashOperations.entries(DefaultBoundHashOperations.java:101) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:233) ~[spring-session-1.0.2.RELEASE.jar:na]
at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:220) ~[spring-session-1.0.2.RELEASE.jar:na]
at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:141) ~[spring-session-1.0.2.RELEASE.jar:na]
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:276) ~[spring-session-1.0.2.RELEASE.jar:na]
at org.springframework.web.context.request.ServletRequestAttributes.updateAccessedSessionAttributes(ServletRequestAttributes.java:255) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.context.request.AbstractRequestAttributes.requestCompleted(AbstractRequestAttributes.java:48) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:106) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:125) ~[spring-session-1.0.2.RELEASE.jar:na]
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:65) ~[spring-session-1.0.2.RELEASE.jar:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103) ~[spring-boot-actuator-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) [tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) [tomcat-embed-core-8.0.30.jar:8.0.30]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_65]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_65]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.30.jar:8.0.30]
at java.lang.Thread.run(Thread.java:745) [na:1.7.0_65]
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.lang.IllegalStateException: Cannot deserialize BeanFactory with id application:9000: no factory registered for this id
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:39) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
... 49 common frames omitted
Caused by: java.lang.IllegalStateException: Cannot deserialize BeanFactory with id application:9000: no factory registered for this id
at org.springframework.beans.factory.support.DefaultListableBeanFactory$SerializedBeanFactoryReference.readResolve(DefaultListableBeanFactory.java:1428) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_65]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_65]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_65]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_65]
at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1104) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1807) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1706) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1344) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:500) ~[na:1.7.0_65]
at org.springframework.aop.framework.AdvisedSupport.readObject(AdvisedSupport.java:557) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_65]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_65]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_65]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_65]
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1893) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) ~[na:1.7.0_65]
at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:70) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
... 51 common frames omitted
Related to: