Description
openedon Feb 3, 2023
Description
When trying to do a redis quide https://quarkus.io/guides/redis in kotlin I'm getting the following error java.lang.IllegalArgumentException: Unable to encode object of type class java.lang.Long
when using ReactiveValueCommands with Long.
private val countCommands: ReactiveValueCommands<String, Long> = dataSource.value(Long::class.java)
The issue is that io.quarkus.redis.runtime.datasource.Marshaller
constructor is receiving long
as a class hint which then resolves to JsonCodec
, but when Marshaller.codec(Class<?>)
method is called in order to determine a codec, java.lang.Long
is passed as a param. Ultimately the codec cannot be found because Marshaller.codecs
map has a codec for long
, not for java.lang.Long
.
The solution is to do this:
private val countCommands: ReactiveValueCommands<String, Long> = dataSource.value(Long::class.javaObjectType)
instead of this:
private val countCommands: ReactiveValueCommands<String, Long> = dataSource.value(Long::class.java)
It would be easier to use this from kotlin without needing to explicitly specify javaObjectType
.
The reproducer is here in qs-redis module - https://github.com/tjakopan/quarkus-examples-kotlin. In order to reproduce the error, one can comment out line 13 and un-comment line 14 in IncrementService
class and run the tests.
Implementation ideas
io.quarkus.redis.datasource.codecs.Codecs
class could specify a LongCodec, similar to already existing codecs for double, int, String and byte[]. And then the Codecs.getDefaultCodecFor(Class<T>)
method could be changed to:
public static <T> Codec<T> getDefaultCodecFor(Class<T> clazz) {
if (clazz.equals(Double.class) || clazz.equals(Double.TYPE)) {
return (Codec<T>) DoubleCodec.INSTANCE;
}
if (clazz.equals(Integer.class) || clazz.equals(Integer.TYPE)) {
return (Codec<T>) IntegerCodec.INSTANCE;
}
if (clazz.equals(Long.class) || clazz.equals(Long.TYPE)) {
return (Codec<T>) LongCodec.INSTANCE;
}
if (clazz.equals(String.class)) {
return (Codec<T>) StringCodec.INSTANCE;
}
if (clazz.equals(byte[].class)) {
return (Codec<T>) ByteArrayCodec.INSTANCE;
}
// JSON by default
return new JsonCodec<>(clazz);
}
Willing to contribute with this if needed.