Arkadiusz
Arkadiusz

Reputation: 1

KryoException. Stackoverflow occured because of infinite recursion

I have a project where I use RedissonSpringCacheManager with RedissonClient default configuration. I am using @Cacheable annotation to cache Entities (unfortunatelly for now I can't cache DTOs instead of Entities because the project is too big. I also can't modify associations in Entities).

Please check sample code to better explain the issue I have:

Entities with bidirectional association:

@Entity
public class User implements Serializable {
    @Id
    @Column(name = "user_id")
    private Long id;
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = CascadeType.ALL)
    private Set<Address> addresses
}

@Entity
@Table(name = "address")
public class Address implements Serializable { 
    @Id
    private Long id;
    @ManyToOne
    @JoinColumn(name = "user_id", referencedColumnName = "user_id", nullable = false)
    private User user;
}

Cache configuration:

@Bean
CacheManager cacheManager(RedissonClient redissonClient) {
    Map<String,CacheConfig> config = new HashMap<>();
    config.put(users, new CacheConfig(liveTime, idleTime));
    return new RedissonSpringCacheManager(redissonClient, config);
}

Method used for caching:

@Cacheable(cacheNames = users, key = "#p0", condition = "#p0 != null", unless = "#result == null")
public User findById(Long id) {
    return userRepository.findById(id);
}

It was correctly working with Redisson version 3.17.1 After upgrading to redisson 3.23.1 I have such exception on serialization of entity, (when trying to add User into cache, by invoking method findById):

com.esotericsoftware.kryo.KryoException: A StackOverflow occurred. The most likely cause is that your data has a circular reference resulting in infinite recursion. Try enabling references with Kryo.setReferences(true). If your data structure is really more than 1320 levels deep then try increasing your Java stack size. Serialization trace:
addresses (com.test.User)
user (com.test.Address)
addresses (com.test.User)
user (com.test.Address)
addresses (com.test.User)
...

What I already tried is:

1)

SetReferences by extending Kryo5Codec and using the Custom kodec

public class CustomKryo5Codec extends Kryo5Codec {
    @Override
    protected Kryo createKryo(ClassLoader classLoader) {
        Kryo kryo = super.createKryo(classLoader);
        kryo.setReferences(true);
        return kryo;
    }
}

In cacheConfiguration changed

return new RedissonSpringCacheManager(redissonClient, config); 

to

return new RedissonSpringCacheManager(redissonClient, config, new CustomKryo5Codec());

After this change I can successfully save entity in cache, but I can't read it because of org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session

2)

Change codec from Kryo to MarshallingCodec, which was by default used in redisson 3.17.1. In cacheConfiguration changed

return new RedissonSpringCacheManager(redissonClient, config); 

to

return new RedissonSpringCacheManager(redissonClient, config, new MarshallingCoded());

After this change the cache is working as expected, however I am still not sure if that's the best solution.

Please advice if there is any other good workaround?

Upvotes: -2

Views: 971

Answers (1)

Himan Bayan
Himan Bayan

Reputation: 56

is this issue resolved for you. I am getting similar exception while trying to write Map<String,HashMap> using RMap and Redisson client

Upvotes: 1

Related Questions