Search code examples
javaspring-bootredis

Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer


My spring boot project uses spring-boot-starter-data-redis for caching on redis, Oracle database for persistent. It runs perfectly with current version 2.7.6. I've just upgraded to 3.0.5. The source code does change pretty much but this configuration for redis stays the same:

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return RedisCacheManager.builder(redisConnectionFactory)
                .transactionAware()
                .build();
    }

Here is how I use @Cacheable

    @Autowired
    private ConfRepository confRepository;

    @Cacheable(value = "configCache", key = "{#root.methodName, #key}")
    @Override
    public Optional<Config> getByKey(String key) {
        return confRepository.findByKey(key);
    }

I deploy my service with 2 instances. The problem is when a key is put to Cacheable in instance 1 cannot be deserialized by instance 2, i.e in above method, my first request to instance 1 to getByKey with the key key1, my second request to instance 2 also with the key1 should hit the cache (get value from redis and return), but I got the stack trace:

org.springframework.data.redis.serializer.SerializationException: Cannot deserialize
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:84)
    at org.springframework.data.redis.serializer.DefaultRedisElementReader.read(DefaultRedisElementReader.java:46)
    at org.springframework.data.redis.serializer.RedisSerializationContext$SerializationPair.read(RedisSerializationContext.java:272)
    at org.springframework.data.redis.cache.RedisCache.deserializeCacheValue(RedisCache.java:277)
    at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:92)
    at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58)
    at org.springframework.cache.transaction.TransactionAwareCacheDecorator.get(TransactionAwareCacheDecorator.java:80)
    at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73)
    at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:571)
    at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:536)
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:402)
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345)
    at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:702)
    at vn.com.tcbs.h2h.biz.service.impl.ConfigManagerServiceImpl$$SpringCGLIB$$0.getGroupRole(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:211)
    at jdk.proxy2/jdk.proxy2.$Proxy201.getGroupRole(Unknown Source)

Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78)
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36)
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:82)
    ... 219 common frames omitted
Caused by: java.lang.IllegalStateException: Could not identify any active SessionFactory having UUID 0105e7c4-c59a-46a6-a86e-23a65dde6ed6
    at org.hibernate.proxy.pojo.bytebuddy.SerializableProxy.retrieveMatchingSessionFactory(SerializableProxy.java:127)
    at org.hibernate.proxy.pojo.bytebuddy.SerializableProxy.readResolve(SerializableProxy.java:113)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at java.base/java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1190)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2266)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1733)
    at java.base/java.io.ObjectInputStream$FieldValues.<init>(ObjectInputStream.java:2606)
    at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2457)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2257)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1733)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:509)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:467)
    at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:71)
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73)
    ... 221 common frames omitted

Can anybody help me in this situation ?


Solution

  • The issue is that in Hibernate 6, the hibernate object caching is not working. So you need to load the full object if it's FetchType.Lazy and you need Lazy object properties and unproxy the object before caching.

    To unproxy an object use the Hibernate.unproxy method. Updated code:

    @Cacheable(value = "configCache", key = "{#root.methodName, #key}")
    @Override
    public Optional<Config> getByKey(String key) {
        var config = confRepository.findByKey(key);
        var entity = config.isPresent() ? Hibernate.unproxy(config.get(), Config.class) : null;
        return Optional.ofNullable(entity);
    }
    

    I had a similar issue after upgrading to Hibernate 6 in Spring MVC. By unproxy the hibernate object before saving it into the cache solved the issue. Also, with spring security session I need to use record/POJO class for authentication object.

    If issue still persist then use record/POJO class to be stored in cache. Because mapping of different entity also adds hibernate classes to serialization.

    Hibernate 6: Never store hibernate objects to cache when multiple servers uses same cache.

    You can use RedisInsight to browse data stored in redis and inspect to get more details.