koin-annotations icon indicating copy to clipboard operation
koin-annotations copied to clipboard

Allow annotating external module dependencies for fine-grained opt-out from compile checks.

Open Jadarma opened this issue 1 year ago • 4 comments

Is your feature request related to a problem? Please describe. When enabling the KOIN_CONFIG_CHECK flag, the compiler will check the modules for completeness at compile time, which is great. However, I have encountered a gotcha when working with Ktor.

I would like to be able to build dependencies based on the application config, such as a database connection:

@Module
class DatabaseModule {

    @Single(createdAtStart = true)
    fun database(config: ApplicationConfig): Database = Database.connect(config.property("db.url").getString()
}

Since Ktor applications are scoped, there is no place to get the config from globally (and would also make it painful to test), so I register the config at the time of installing the Koin feature and have a reference to the environment:

fun Application.configureDI() {
    install(Koin) {
        modules(module(createdAtStart = true) {
            single { environment.config }
        })
        modules(DatabaseModule().module)
    }
}

This works perfectly at runtime, but the compilation now fails because KSP can't know that I will provide a separate module with the dependency at runtime or not.

Describe the solution you'd like I do not want to disable the entire KSP checks for this one workaround. Instead, I would like to have an annotation that allows me to opt out of a check for a particular inject, and that it should just assume that it is available when validating the rest of the module.

This would document in code that I intentionally defined an external dependency and I am aware that I am responsible for ensuring its runtime availability, something like:

@Module
class DatabaseModule {

    @Single(createdAtStart = true)
    fun database(@External config: ApplicationConfig): Database = Database.connect(config.property("db.url").getString()
}

Describe alternatives you've considered I have tried to see if it is possible to pass the config as a constructor parameter to the module, but code generation does not like it, and it makes sense since that would break the @Module(includes = []) feature, which expects a class reference with a no-args constructor.

I also tried to include the config module into the database module programatically, and while it works at runtime, it is again too late because the issue happens at compile time.

Target Koin project Koin Annotations

Jadarma avatar Oct 21 '23 12:10 Jadarma

Still wondering why you can't access a definition that would be included in your Koin ktor app module?

Or is it more here a problem of mixing Annotated/DSL config?

arnaudgiuliani avatar Jan 30 '24 10:01 arnaudgiuliani

is it more here a problem of mixing Annotated/DSL config?

Yes.

I can access the definition at runtime, and everything works as expected from a DI point of view. The issue is static compile checks enabled by KOIN_CONFIG_CHECK only scan in the context of a @Module and since I cannot get an instance of Ktor's ApplicationConfig from a global context, only from an instance of Application, I cannot register it directly in the module and must therefore provide it via the DSL, where I do have access to it.

While this mixing of annotations and DSL would work at runtime, the KOIN_CONFIG_CHECK does not know when, where, how, and if I will provide a dependency via the DSL and correctly reports it, failing the compilation. However, that leaves me no workaround other than to disable the checks entirely, which is why I proposed the @External or similar mechanism to allow me to tell the plugin: "Yes, I know this might fail at runtime, but I explicitly made sure to configure it in the DSL, treat this as a false positive", while still having it check everything else for actual user error.

Jadarma avatar Jan 30 '24 12:01 Jadarma

ok, something that would be "ignored" for safety check

arnaudgiuliani avatar Jan 30 '24 12:01 arnaudgiuliani

I have the same problem :(

cmdjulian avatar Mar 24 '24 00:03 cmdjulian

I am having a similar issue here https://github.com/InsertKoinIO/koin-annotations/issues/126

steve1rm avatar May 31 '24 04:05 steve1rm

the global idea is accepted. Don't know yet if we can call it @External or something else. I keep you posted.

arnaudgiuliani avatar Jun 25 '24 13:06 arnaudgiuliani

Same issue here - It would be good to have a way to exclude certain deps from compiler checks

igorwojda avatar Jun 27 '24 09:06 igorwojda

In the compiler we have a notion of "external dependencies" now, that we can scan across multiple Gradle module. See https://github.com/InsertKoinIO/koin-annotations/pull/135.

I propose @Provided annotation. I'm afraid it confuses with Dagger's @Provided. What do you think? Else @Declared that would resonate more about something declared in Koin?

arnaudgiuliani avatar Jul 12 '24 16:07 arnaudgiuliani

Here is a PR with @Provided type: https://github.com/InsertKoinIO/koin-annotations/pull/140

arnaudgiuliani avatar Jul 15 '24 10:07 arnaudgiuliani

@arnaudgiuliani , I updated my personal repo to use the new annotation Provided, the weird thing is the compilation check is not behaving as expected with the newest version. I opened a PR to show this behavior -> https://github.com/gabrielbmoro/MovieDB-App/pull/162/files

gabrielbmoro avatar Jul 17 '24 18:07 gabrielbmoro