lettuce icon indicating copy to clipboard operation
lettuce copied to clipboard

Refactor optional dependencies into separate modules

Open mgroth0 opened this issue 2 years ago • 1 comments

I want to start by saying this is an incredibly useful library. It is helping me learn how to use Redis and implement it in an asynchronous way, and I'm very grateful for it.

Feature Request

I have checked the wiki and searched the issues here, and I did not find any discussion on why there are optional dependencies in the pom.xml. My understanding is that optional dependencies reduce stability because they allow the possibility of a java.lang.NoClassDefFoundError to be thrown if the user did not manually include the depednencies they require.

Is your feature request related to a problem? Please describe

This comes up for me in the following way:

java.lang.NoClassDefFoundError: kotlinx.coroutines.reactive.AwaitKt
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invokeSuspend(BaseApplicationEngine.kt:123)
	at io.ktor.server.application.hooks.CallFailed$install$1$1.invokeSuspend(CommonHooks.kt:43)
	at io.ktor.server.application.hooks.CallFailed$install$1.invokeSuspend(CommonHooks.kt:42)
	at io.ktor.util.pipeline.PipelineKt$execute$2.invokeSuspend(Pipeline.kt:478)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invokeSuspend(DefaultEnginePipeline.kt:118)
Caused by: java.lang.NoClassDefFoundError: kotlinx.coroutines.reactive.AwaitKt
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invokeSuspend(BaseApplicationEngine.kt:123)
Caused by: java.lang.NoClassDefFoundError: kotlinx.coroutines.reactive.AwaitKt
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at io.ktor.util.pipeline.PipelineKt$execute$2.invokeSuspend(Pipeline.kt:478)
	at io.ktor.server.routing.Routing.executeResult(Routing.kt:188)
	at io.ktor.server.routing.Routing$Plugin$install$1.invokeSuspend(Routing.kt:140)
	at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invokeSuspend(BaseApplicationEngine.kt:123)
	at io.ktor.server.application.hooks.CallFailed$install$1$1.invokeSuspend(CommonHooks.kt:43)
	at io.ktor.server.application.hooks.CallFailed$install$1.invokeSuspend(CommonHooks.kt:42)
	at io.ktor.util.pipeline.PipelineKt$execute$2.invokeSuspend(Pipeline.kt:478)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invokeSuspend(DefaultEnginePipeline.kt:118)
	at io.ktor.util.pipeline.PipelineKt$execute$2.invokeSuspend(Pipeline.kt:478)
	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:119)
Caused by: java.lang.ClassNotFoundException: kotlinx.coroutines.reactive.AwaitKt
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
	at io.lettuce.core.api.coroutines.RedisHashCoroutinesCommandsImpl.hget(RedisHashCoroutinesCommandsImpl.kt:42)
	at io.lettuce.core.api.coroutines.RedisCoroutinesCommandsImpl.hget$suspendImpl(RedisCoroutinesCommandsImpl.kt)
	at io.lettuce.core.api.coroutines.RedisCoroutinesCommandsImpl.hget(RedisCoroutinesCommandsImpl.kt)

I can solve this by manually adding a dependency on org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.7.0-Beta.

Describe the solution you'd like

According to the Maven Docs, optional dependencies are not ideal and not the cleanest solution. Ideally, the project would be split into multiple modules. If we want to keep Lettuce-Core minimal, we don't need to make it depend on kotlinx-coroutines-reactive. But then all features that rely on that dependency should be in a separate module. I want to know that if my code compiles, that all classes can be found at runtime. I generally assume that all of the libraries I use follow this contract, and it is abnormal that lettuce does not.

Describe alternatives you've considered

Lettuce-core could have a normal dependency on org.jetbrains.kotlinx:kotlinx-coroutines-reactive. However, I can understand the drawbacks of this since it could increase the size of lettuce-core with bloated sub-dependencies that many users may not need.

Teachability, Documentation, Adoption, Migration Strategy

Looking at maven, it seems there is currently only one lettuce module. It would be nice to see lettuce-core alongside lettuce-coroutines (which could itself depend on the core module).

mgroth0 avatar Mar 19 '23 22:03 mgroth0

Thanks for your suggestion. Maintaining two modules outweighs the benefits in terms of complexity and maintenance. We support many optional dependencies, such as HdrHistogram, native transports and many more. What would make sense is having a Wiki page outlining what dependencies are required to simplify the getting started experience. Paging @sokomishalov for visibility.

mp911de avatar Mar 20 '23 08:03 mp911de