Skip to content
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

Issue with Kryo5Codec in combination with org.springframework.cache.support.NullValue #5830

Open
MrKanister2000 opened this issue Apr 30, 2024 · 5 comments
Labels

Comments

@MrKanister2000
Copy link

Hi,

I'm currently having an issue with the Spring Cache implementation in combination with Redisson.
The JCacheCache class provided by Redisson extends org.springframework.cache.support.AbstractValueAdaptingCache. In the method protected Object fromStoreValue(@Nullable Object storeValue) of the class AbstractValueAdaptingCache, there is an if condition, that check if the storeValue is equal to NullValue.INSTANCE using ==.

protected Object fromStoreValue(@Nullable Object storeValue) {
	if (this.allowNullValues && storeValue == NullValue.INSTANCE) {
		return null;
	}
	return storeValue;
}

This condition evaluated to false in my case, because the instance of storeValue was not the same instance as NullValue.INSTANCE. Reason is the deserialisation, that was done by Kryo. It seems, that Kryo changes the constructor to "public" using reflections and creates a new instance by calling the constructor. It does not call the "readResolve()" method of NullValue class, which would return NullValue.INSTANCE.
Is this a known issue? The only solution I came up with is extending the Kryo5Codec and adding a custom Serializer for NullValue.class. Is there another way to fix this issue?

Best regards

@mrniko
Copy link
Member

mrniko commented Apr 30, 2024

The JCacheCache class provided by Redisson

Sorry, Redisson doesn't implement such class

@MrKanister2000
Copy link
Author

Sorry, Redisson doesn't implement such class

Yep sry, my bad. I got confused with the class names. JCacheCache is part of the Spring package.
Nevertheless, the org.redisson.jcache.JCache class returns a new instance of NullValue from the cache, because of the Kryo deserialization issue I described. Any hint how to fix this?

@mrniko
Copy link
Member

mrniko commented Apr 30, 2024

Can you add the code below into org.redisson.codec.Kryo5Codec#createKryo method and say if it works?

if (com.esotericsoftware.kryo.util.Util.isClassAvailable("org.springframework.cache.support.NullValue")) {
   kryo.addDefaultSerializer(Class.forName("org.springframework.cache.support.NullValue"), new JavaSerializer());
}

@MrKanister2000
Copy link
Author

Yes, it works, thanks. Do you see any trade-offs (like performance) when using the JavaSerializer?

My first solution was extending the Kryo5Codec class:

public class MyKryo5Codec extends Kryo5Codec {

    @Override
    protected Kryo createKryo(ClassLoader classLoader) {
        Kryo kryo = super.createKryo(classLoader);

        kryo.addDefaultSerializer(NullValue.class, new NullValueSerializer(kryo, NullValue.class));

        return kryo;
    }
}

and creating a custom NullValueSerializer:

public class NullValueSerializer extends FieldSerializer<NullValue> {

    public NullValueSerializer(Kryo kryo, Class type) {
        super(kryo, type);
    }

    @Override
    public NullValue read(Kryo kryo, Input input, Class type) {
        return (NullValue) NullValue.INSTANCE;
    }
}

But your solution has a way smaller footprint than mine.

@mrniko
Copy link
Member

mrniko commented May 1, 2024

Thanks for testing. In your example Spring become a required dependency because of explicit NullValue class definition which I would like to avoid. It would be great if you rewrite it without explicit NullValue definition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants