https://kotlinlang.org logo
#kodein
Title
j

Jorge Castillo

03/12/2019, 10:44 AM
@salomonbrys, is Kodein usable just in library modules? I’ve integrated it just in a library module but don’t want my app (android) module to know anything about it, since it’d be a library used by third parties. I’m getting this compile time error:
s

salomonbrys

03/12/2019, 10:46 AM
How did you import the Kodein-DI lib in your library module's gradle file ?
j

Jorge Castillo

03/12/2019, 10:46 AM
implementation “org.kodein.dikodein di generic jvm$kodein_version” implementation “org.kodein.dikodein di framework android$kodein_version”
don’t want it to be
api
since don’t want to expose its APIs to the third party, if possible
my lib has proper access to the Kodein classes etc, everything is alright but then I get the mentioned compile time error. I solve it by adding those deps to the app module (I’ve tried and works) but that’s something I’d want to avoid at all cost
s

salomonbrys

03/12/2019, 10:48 AM
Can you try with
api
, just to see if it fixes the issue ?
j

Jorge Castillo

03/12/2019, 10:48 AM
don’t want third parties to require Kodein
api
also fixes it, at least for a local gradle third party module
I assume it’d also work for external third parties that fetch our library whenever we deploy it to maven central
s

salomonbrys

03/12/2019, 10:49 AM
Well, Kodein needs to be in the classpath of the app
j

Jorge Castillo

03/12/2019, 10:49 AM
ideally, the
app
module (working as a third party here) would never need to fetch Kodein
s

salomonbrys

03/12/2019, 10:50 AM
I see. That is not possible. Kodein needs to be in the class path.
j

Jorge Castillo

03/12/2019, 10:50 AM
do you think something could be done to workaround that ?
as in opening a PR to Kodein if needed
to remove that requirement somehow
s

salomonbrys

03/12/2019, 10:51 AM
No. That is simply not possible. If a library uses Kodein, the app runing the lib must contain the Kodein code.
Cano you try to declare the dep with
runtimeOnly
instead of
implementation
?
Forget it, bad idea
Won't work
j

Jorge Castillo

03/12/2019, 10:52 AM
ok
no, it does not work 😄
so why is it impossible?
s

salomonbrys

03/12/2019, 10:53 AM
According to this, using
implementation
should work, as the app should fetch it for runtime, not for compile time : https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph
j

Jorge Castillo

03/12/2019, 10:54 AM
🤷‍♂️
s

salomonbrys

03/12/2019, 10:54 AM
Oh. Just saw that you are getting a compile time error. I thought it was a runtime error 😛
j

Jorge Castillo

03/12/2019, 10:55 AM
it’s a compile time one 🙂
s

salomonbrys

03/12/2019, 10:55 AM
I see. So let's start again (sorry).
j

Jorge Castillo

03/12/2019, 10:55 AM
ok hehe, no worries
s

salomonbrys

03/12/2019, 10:55 AM
So : this is expected. There's no way to fix it, other than NOT having your library classes be
KodeinAware
.
j

Jorge Castillo

03/12/2019, 10:56 AM
for now I got it to work just with 2 approaches: • explicitly add the Kodein deps into the third party: Given it’s a library we have and we’re using Kodein in house just for our benefit on architecting it, we’d want to not expose it. • Use
api
for Kodein deps inside our lib so they get exposed to the third party classpath. Doable but not ideal since third party would not need to even see those in the auto complete etc
that could work
I mean, what would be the equivalent setup without using KodeinAware?
s

salomonbrys

03/12/2019, 10:58 AM
In essence, this is not a huge limitation: instead of:
Copy code
class Whatever(override val kodein: Kodein) : KodeinAware {
  val myDep: MyDep by instance()
}
Do:
Copy code
class Whatever(private val kodein: Kodein) {
  val myDep: MyDep by kodein.instance()
}
j

Jorge Castillo

03/12/2019, 10:58 AM
the thing is it’s android 😄
can I just create a kodein manually in the application class or something ? can’t get it passed in
s

salomonbrys

03/12/2019, 11:00 AM
Then it's a tad more complex:
Copy code
class Whatever {
  val myDep: MyDep by lazy { kodein().direct.instance() }
}
And, if you want to be a bit more optimised:
Copy code
class Whatever {
  val kodein by lazy { appKodein() }
  val myDep: MyDep by lazy { kodein.direct.instance() }
}
Also, you can use the dependency holder pattern : http://kodein.org/Kodein-DI/?6.1/android#dependency-holder
j

Jorge Castillo

03/12/2019, 11:03 AM
I see, I’ll take a look, thanks!
s

salomonbrys

03/12/2019, 11:05 AM
Finally, you could create a "local dependency holder":
Copy code
class Whatever {
  private class Deps(override val kodein: Kodein) : KodeinAware {
    val myDep: MyDep by instance()
  }
  private val deps: Deps by lazy { Deps(kodein()) }
}
Any of these should work 😛 Keep me posted 😉
j

Jorge Castillo

03/12/2019, 11:07 AM
sure, thx 🙂
yep, looks like it compiles
s

salomonbrys

03/12/2019, 11:10 AM
\o/ Which solution did you implemented ?
j

Jorge Castillo

03/12/2019, 11:14 AM
for now just the simple one without de holder
s

salomonbrys

03/12/2019, 11:14 AM
👍
j

Jorge Castillo

03/12/2019, 11:15 AM
just trying out things, as soon as everything is working (fixing some runtime erros I had on the implementation now) I’d iterate it towards the holder pattern if possible
that by lazy seems to be returning a viewModelFactory
sorry
s

salomonbrys

03/12/2019, 11:15 AM
?
j

Jorge Castillo

03/12/2019, 11:15 AM
a
KodeinProperty<Deps>
how can I get access to the actual item ?
private val deps: Deps by lazy { Deps(kodein()) }}
s

salomonbrys

03/12/2019, 11:16 AM
use
.direct
j

Jorge Castillo

03/12/2019, 11:16 AM
where? not available over the property
s

salomonbrys

03/12/2019, 11:16 AM
Can you show me the code ?
j

Jorge Castillo

03/12/2019, 11:16 AM
(might be bc we’re using 5.0.0)
Copy code
val kodein by lazy {
        Kodein { import(appModule(Deps())) }
 }
private val viewModelFactory by lazy { kodein.instance<ViewModelProvider.Factory>(tag = AppQualifier) }

...
override fun onCreate() {
    viewModel = getViewModel(viewModelFactory)
}
something like that
s

salomonbrys

03/12/2019, 11:18 AM
Copy code
private val viewModelFactory by lazy { kodein.DIRECT.instance<ViewModelProvider.Factory>(tag = AppQualifier) }
j

Jorge Castillo

03/12/2019, 11:18 AM
ah, ok
s

salomonbrys

03/12/2019, 11:19 AM
(
.direct
in lowercase, obviously)
j

Jorge Castillo

03/12/2019, 11:19 AM
what does direct exactly ?
s

salomonbrys

03/12/2019, 11:19 AM
It returns the required instance, instead of a
KodeinProperty
, which is meant to be used with
by
j

Jorge Castillo

03/12/2019, 11:20 AM
but it stays lazy isn’t it ?
s

salomonbrys

03/12/2019, 11:21 AM
Well,
lazy
expects the instance. Using
by instance()
is a way of being lazy without writing
by lazy {}
everytime.
j

Jorge Castillo

03/12/2019, 11:21 AM
ok
makes sense