gouline / kapsule Goto Github PK
View Code? Open in Web Editor NEWMinimalist dependency injection library for Kotlin
License: MIT License
Minimalist dependency injection library for Kotlin
License: MIT License
Hello,
It seems I found a bug or a limitation on transitive dependencies between 2 modules:
class Deps(
a: DependenciesA,
b: DependenciesB
) : DependenciesA by a, DependenciesB by b, HasModules {
override val modules = setOf(a, b)
}
interface DependenciesA {
val foo: String
val foobar: String
}
class ModuleA : DependenciesA, Injects<Deps> {
override val foo: String = "foo"
override val foobar: String by required { foo + bar }
}
interface DependenciesB {
val bar: String
}
class ModuleB : DependenciesB, Injects<Deps> {
override val bar: String by required { if (foo == "foo") "bar" else "i dont know" }
}
val deps = Deps(ModuleA(), ModuleB()).transitive()
The dependency flow is: a.foobar -> b.bar -> a.foo
Result: When injecting Deps.a.foobar
, it throws a NPE because b.bar is null.
I didn't dig into Kapsule, but I think it makes sense because when ModuleA
is built, all dependencies are resolved directly, with a dependency on ModuleB
which has itself a dependency on ModuleA
.
An easy fix would be to split dependencies into 3 modules, in order to not have a "cyclic dependency on Module level". However it would be nice to support this, because this is fine on dependency level.
What do you think?
Thanks.
Is there any plans to support Kotlin Multiplatform? It looks like a suitable approach (library) when building KMP projects.
Thanks in advance.
The root readme have dead links for the documentation part
Hi!
Really great stuff here, love how simple it is to use and how concise the code base is compared to other dependency injection libraries out there.
However, looking through your code, I noticed you’re extending WeakHashMap to allow for a simple caching mechanism of the last value stored, and I couldn’t help myself but wondering if keeping this reference outside of the “actual” map implementation could result in a leak somehow.
Imagine the following:
class HomeModule(private val activity: HomeActivity) {
// EDITED: Typo had this return a HomeModule before ...
val model by lazy { HomeModel(activity) }
}
Now, in our activity:
class HomeActivity : Activity, Injects<HomeModule> {
private val model by required { model }
}
So far so good. However, when we move away from the HomeActivity
, and given that we don’t do any injection in our next activity, then there will be a hard reference to the HomeModule, and therefore also the HomeActivity, which won’t get collected by the garbage collector.
I suppose it's only a valid issue for the last stored key/value pair, seeing as you're extending WeakHashMap
.I suspect that's also why you did just that.
Now, if you already thought about this for the last key/value pair as well and have a solution already in your codebase, then please correct me. :smile:
With your solution, how would you manage the dependencies between modules?
For example, ModuleA
exposes a retrofit (Retrofit.Builder().[…].build()
) and ModuleB
exposes the API by using this retrofit object (retrofit.create(MyApi::class.java)
).
Should ModuleB
implements Injects<ModuleA>
or will you give someway ModuleA
a reference to ModuleB
?
I’ve checked the samples on GitHub but I can’t see the proper way to manage this.
Source: https://medium.com/@lcor1979/very-nice-solution-c4410253e712 (@lcor1979)
Here is a simple example with an injected property where I want to use the injected property to define another property:
class TestModule
{
val bar = "bar"
}
class Test(module: TestModule): Injects<TestModule>
{
init { inject(module) }
val foo by required { bar }
val foobar = "testing " + foo
}
fun main(args: Array<String>) { println(Test(TestModule()).foobar) }
Running this gives an exception:
Exception in thread "main" kotlin.KotlinNullPointerException
at space.traversal.kapsule.Delegate$Required.getValue(Delegate.kt:44)
at com.nobleworks_software.gmail_handler.Test.getFoo
at com.nobleworks_software.gmail_handler.Test.<init>
i have verified that the call to inject happens before the foobar expression is evaluated and that the lambda passed to required is never invoked.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.