question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

The problem with cyclic injects checker

See original GitHub issue

Hello! Unfortunately, I got an unexpected crash with toothpick.

How to reproduce the crash

val parentScope = KTP.openScope("App")
val childScope = KTP.openScopes("App", "Child")

childScope.installModules(module {
   bind(...) // here is I bind some isolated(internal) instances that I need only in "Child" scope
   bind(IFace::class.java).to(Face::class.java).singleton() // also I bind some Interface to provide outside (like dagger's component)
})

// I want to provide some interface from my child scope to parent scope
parentScope.installModules(module {
    bind(IFace::class.java).toProviderInstance { childScope.getInstance(IFace::class.java) }.providesSingleton()
})

this code throws

Class xxx.xxx.IFace creates a cycle:

                              ===============================
                             ||                             ||
                             \/                             ||
   xxx.xxx.IFace  ||
                             ||                             ||
                              ===============================

this code is working, but it creates instance immediately

     bind(IFace::class.java).toInstance(childScope.getInstance(IFace::class.java)).singleton()

If I remove any cycles checking from toothpick, everything is working as I expected

the problem with this code from RuntimeCheckOnConfiguration.java

final LinkedHashSet<Pair> linkedHashSet = cycleDetectionStack.get();
if (linkedHashSet.contains(pair)) { // pair = IFace|null
  throw new CyclicDependencyException(Pair.getClassList(linkedHashSet), clazz);
}

we are trying to get IFace instance from child scope, but we already trying to get it from parent scope cycles checking code can’t understand it 😃

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:6

github_iconTop GitHub Comments

1reaction
mordercommented, Sep 29, 2020
parentScope.installModules(module {
    bind(IAdsManager::class.java).toProviderInstance { scope.getInstance(IAdsManager::class.java) }.providesSingleton()
})

Here is I want to bind an interface without creating of instance right now. Because it’s possible that IAdsManager will never instantiate because we don’t open some screen. For example, I open some screen (ViewModel), with injected IAdsManager, and then I call IAdsManager.init() to do network request. I want to do the job(create an instance of a manager) when it needed, for example when ViewModel is instantiated.

IAdsManager - it’s just for example. Overall I’m talking about an approach to solve this problem.

This code is solving the problem, but it creates the instance right in the app. I don’t like it.

parentScope.installModules(module {
    bind(IAdsManager::class.java).toProvider(scope.getInstance(IAdsManager::class.java)).singleton()
})

PS: To remind what I have tried to explain early, a top scope of a tree, cannot/must not depend from one of its child, because by design this top scope may have other children or no child at all, and it should be kept persistent.

I agree, and I think the toothpick is not designed to solve my problem clearly.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dependency Injection With Cyclic Dependencies | The Miners
When using DI we isolate the construction of dependencies in a single place we call composition root or container and then the code...
Read more >
Circular Dependencies in Spring - Baeldung
A quick writeup on dealing with circular dependencies in Spring: how they occur and several ways to work around them.
Read more >
Circular Dependencies in Dependency Injection - Medium
A description of how we solved a circular dependency in our dependency injection, and some of the software principles involved.
Read more >
Dealing With Circular Dependency Injection References
Your main problem there is you are breaking dependency injection by manually injecting dependencies. It does solve the DI blowing up, but IMO ......
Read more >
NG0200: Circular dependency in DI detected while ... - Angular
Debugging the errorlink ... Use the call stack to determine where the cyclical dependency exists. You will be able to see if any...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found