Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I easily cache Kotlin Objects in Redis using json via Jackson?

I have a Spring boot app written in Kotlin where I would like to enable caching in Redis. I'd like to have the objects stored as serialized JSON and ideally don't want to have to register each type that could be potentially cached. I have some configuration that mostly works, with a big caveat.

@Bean
fun redisCacheConfiguration(): RedisCacheConfiguration {
    val objectMapper =
        ObjectMapper()
            .registerModule(KotlinModule())
            .registerModule(JavaTimeModule())
            .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)

    val serializer = GenericJackson2JsonRedisSerializer(objectMapper)

    return RedisCacheConfiguration
        .defaultCacheConfig()
        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
}

I'm having a little trouble understanding the different values for DefaultTyping but NON_FINAL seems to be the most expansive. However, since objects in Kotlin are final by default, this only works for objects flagged as "open". Ideally I'd like to avoid having to "open" objects just so they can be cached.

Is there some other way I can make this work?

like image 478
AwesomeTown Avatar asked Dec 24 '22 04:12

AwesomeTown


1 Answers

I had the same problem. You should use "open" classes. But this will not help you with data classes, because you cannot make them "open".
There is a plugin called "all-open" where you can define annotations. If you use these annotations classes become "open", even data classes.

spring-kotlin plugin uses "all-open" plugin under the hood, so spring annotations like @Service, @Component etc. make classes open for AOP, because proxying requires you to inherit from classes.

If you use spring-kotlin plugin, there is nice annotation that makes sense for you problem, it is used in Spring Cache, its name is @Cacheable. If you use @Cacheable on your classes, they will become open and save their type-info to json (ex: {@class: "com.example.MyClass", ...}) when you include this code:

    val objectMapper =
    ObjectMapper()
        .registerModule(KotlinModule())
        .registerModule(JavaTimeModule())
        .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)

val serializer = GenericJackson2JsonRedisSerializer(objectMapper)

More details: https://kotlinlang.org/docs/reference/compiler-plugins.html

Shortly: You don't have to do anything except adding @Cacheable annotation to the classes you want, and it fits by sense also IMO.

like image 133
MrKnyaz Avatar answered Dec 28 '22 08:12

MrKnyaz