-
Notifications
You must be signed in to change notification settings - Fork 40.2k
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
Spring Session and Dev Tools Cause ClassCastException #3805
Comments
Similar problem with other caches whose content survive the application refresh. |
probably not. Each cache implementation has its own way of deserializing cached data but I guess we could maybe tune the config when devtools runs. I am not sure if that's a huge problem though, persistent caching in dev mode seems like a lousy option. We had an issue with our SpringOne demo that I need to dig a bit more. I'll create a separate issue if necessary. Thanks! |
Unfortunately I've not found a way to work around this type of issue without making changes in the things that call |
So if you want Redis, it's not possible to use the dev-tools anymore? I'm facing the same error, which took me hours to find out (spring beginner). |
As things stand you can't use Spring Session backed by Redis and DevTools together.
I'm sorry that you spent hours finding this out. It's certainly not the experience that we want beginners to have. This is mentioned in the known limitations section of the documentation, but perhaps you didn't see the description or it didn't mean much too you? I'm wondering if we would be better failing fast when we detect the Spring Session, Redis, and DevTools combination with a message explaining that it won't work. |
Thanks for your reply. Yes, you're right. The documentation was the answer, but to be honest, if you start with spring there is so much you take notice from and try to remember. I don't think it's a doc update worth. |
This can be resolved for Spring Session and Spring Data Redis once DATAREDIS-427 is resolved. Perhaps a bump to @christophstrobl could make that happen? A workaround for this when using Spring Session 1.1.0.M1+ can be found in spring-state-securing-restful-apis. Using the latest GA is slightly more complex to ensure the custom @Configuration
class SpringSessionConfig {
@Bean
public RedisSerializer<Object> defaultRedisSerializer() {
return new BeanClassLoaderAwareJdkRedisSerializer();
}
@Autowired
public void configureSessionRedisTemplate(RedisTemplate<String,ExpiringSession> sessionRedisTemplate, RedisSerializer<Object> serializer) {
sessionRedisTemplate.setDefaultSerializer(serializer);
}
static class BeanClassLoaderAwareJdkRedisSerializer implements RedisSerializer<Object>, BeanClassLoaderAware {
private Converter<Object, byte[]> serializer = new SerializingConverter();
private Converter<byte[], Object> deserializer;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.deserializer = new DeserializingConverter(new DefaultDeserializer(classLoader));
}
public Object deserialize(byte[] bytes) {
if (ObjectUtils.isEmpty(bytes)) {
return null;
}
try {
Object result = deserializer.convert(bytes);
return result;
} catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
}
public byte[] serialize(Object object) {
if (object == null) {
return new byte[0];
}
try {
return serializer.convert(object);
} catch (Exception ex) {
throw new SerializationException("Cannot serialize", ex);
}
}
}
} |
While we're waiting on some changes in Spring Data Redis and Spring Session, we could probably auto-configure this workaround in DevTools. |
I refer to this link to resolve my problem: http://stackoverflow.com/questions/2591779/cast-across-classloader, however I don't know why one class is read into ObjectOutputStream then written into ObjectInputStream can change its classloader. |
FYI same problem with Apache Ignite; add an object to an Ignite cache in the restartedMain and get from cache in another thread (embedded Tomcat nio thread) with launcher classloader and get a CCE. Don't use devtools and problem goes away. This is on Boot 1.5.4 and Ignite 2.0.0 |
If Spring Session Redis and Spring Boot Dev Tools are being used and a user defined class is persisted into HttpSession a ClassCastException will occur when trying to load it.
The problem is that Spring Session uses Spring Data Redis to load the class on each request. Spring Data Redis eventually uses
DefaultDeserializer
which uses anObjectInputStream
to load the class from the systemClassLoader
.This means that the value restored from session has a class defined by the system
ClassLoader
. The application itself loads the same class from Spring Boot'sRestartClassLoader
. Since the two classes are loaded from differentClassLoader
s they cannot be cast from one to the other.One possible solution is for Spring Redis to use a mechanism to customize the
ObjectInputStream
ClassLoader
to use theThreadLocal.getThread().getContextClassLoader()
. For example, it could useConfigurableObjectInputStream
I believe one alternative is that if
DefaultDeserializer
were loaded usingRestartClassLoader
, then theObjectInputStream
should use theRestartClassLoader
.Related (possibly replaces this issue): SPR-13409
The text was updated successfully, but these errors were encountered: