Issue
In our spring boot application, we use Hazelcast as distributed cache. There are some times that it is forgotten to be changed the serialVersionUID on the objects that are cached and this has as a result to have way a lot of exceptions and our alerts to go crazy from the error bellow.
java.io.InvalidClassException: com.company.service.server.domain.SomeObject; local class incompatible: stream classdesc serialVersionUID = -5387655287348283785, local class serialVersionUID = -1803841624490656210
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2002)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1849)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2159)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1666)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:502)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:460)
at com.hazelcast.internal.serialization.impl.JavaDefaultSerializers$JavaSerializer.read(JavaDefaultSerializers.java:84)
at com.hazelcast.internal.serialization.impl.JavaDefaultSerializers$JavaSerializer.read(JavaDefaultSerializers.java:77)
at com.hazelcast.internal.serialization.impl.StreamSerializerAdapter.read(StreamSerializerAdapter.java:48)
at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toObject(AbstractSerializationService.java:187)
at com.hazelcast.map.impl.proxy.MapProxySupport.toObject(MapProxySupport.java:1237)
at com.hazelcast.map.impl.proxy.MapProxyImpl.get(MapProxyImpl.java:120)
at com.hazelcast.spring.cache.HazelcastCache.lookup(HazelcastCache.java:162)
at com.hazelcast.spring.cache.HazelcastCache.get(HazelcastCache.java:67)
I was trying to find a way to handle this better and centrally. So every time that something similar will happen we will just evict the incompatible object from cache through the code.
I found that spring boot provides an interface to override for error handing which is: org.springframework.cache.interceptor.CacheErrorHandler .
package org.springframework.cache.interceptor;
import org.springframework.cache.Cache;
import org.springframework.lang.Nullable;
public interface CacheErrorHandler {
void handleCacheGetError(RuntimeException var1, Cache var2, Object var3);
void handleCachePutError(RuntimeException var1, Cache var2, Object var3, @Nullable Object var4);
void handleCacheEvictError(RuntimeException var1, Cache var2, Object var3);
void handleCacheClearError(RuntimeException var1, Cache var2);
}
But this interface is only for handing runtime exceptions and not checked exceptions as the InvalidClassException is.
Does anyone have any other idea on how to approach it with a central and clean way?
Solution
Based on this thread, Hazelcast wraps all the InvalidClassException to a runtime HazelcastSerializationException and it is possible to handle them. See this thread for more information https://github.com/spring-projects/spring-framework/issues/26587
Answered By - PavlMits
Answer Checked By - Clifford M. (JavaFixing Volunteer)