I have two classes, Foo<T>
and Bar
, which depend on each other, as well as various other classes. I am using Dagger-2 for dependency injection, but if I naively add the circular dependency, Dagger hits a stack overflow at runtime. What's a good way to refactor the classes to fix this, while still using Dagger to inject all the other dependencies, and with minimal duplication and changes to existing calls?

- 19,190
- 8
- 63
- 98

- 1,720
- 1
- 13
- 35
3 Answers
The easy way out is to use Lazy<T>
on one side.
Lazy<Foo> foo;
@Inject
Bar(Lazy<Foo> foo) {
this.foo = foo;
}
// use foo.get(); when needed

- 79,669
- 27
- 256
- 428
-
Wait -- why would that work? Wouldn't it still end up in a loop whenever you called `get`? – Jesse W at Z - Given up on SE Jun 22 '17 at 22:19
-
4If you call `get()` only when you actually use it, then one side initializes itself, while the other only initializes *later*. Just don't call `.get()` in the constructor. I've done this before and it works, but it's the easy way out. – EpicPandaForce Jun 22 '17 at 22:36
-
OK, so when you actually use it (i.e. call `foo.get()`) Dagger needs to construct instances of the dependencies of `Foo`, which include a *new* instance of `Bar`, which requires a new instance of `Lazy
` -- but that's where the loop terminates? – Jesse W at Z - Given up on SE Jun 22 '17 at 22:45 -
Well it includes a new instance of Bar only if they're both unscoped - in my case, they were both scoped. I *think* it should still work if they're both unscoped, but I'd have to check to make sure. – EpicPandaForce Jun 22 '17 at 23:07
-
1It seemed to work when I tried it, with them both unscoped. – Jesse W at Z - Given up on SE Jun 26 '17 at 16:56
-
21Just note, that if you use kotlin, you should import `dagger.Lazy` instead of `kotlin.Lazy`. – Kamo Spertsian Jul 30 '18 at 07:49
-
Replace `Lazy
` foo with `Provider – LiTTle Jun 28 '22 at 11:24foo`. All the other are the same, you still get the actual value by calling `get`. [More info for Provider](https://docs.oracle.com/javaee/6/api/javax/inject/Provider.html).
After an excessive amount of thought and talks with coworkers, we ended up doing the following:
class Foo<T> extends FooWithoutDep<T> {
@Inject Foo(Bar bar, OtherDep1 dep1, OtherDep2 dep2) {
super(dep1, dep2);
setBarDep(bar);
}
}
class FooWithoutDep<T> {
//Field declarations elided
@Inject FooWithoutDep(OtherDep1 dep1, OtherDep2 dep2) {
//Normal constructor stuff
}
void setBarDep(Bar bar) { this.bar = bar; }
//The rest of the actual logic
}
class Bar {
//Field declarations elided
@Inject Bar(FooWithoutDep<Thing> foo, OtherDep3 dep3) {
this.foo = foo;
this.foo.setBarDep(this);
this.dep3 = dep3;
}
//Code that uses Foo and the other dependencies
}
Explaining this -- we moved the actual logic of Foo into a parent class (FooWithoutDep), that took the circular dependency as a settable field rather than a constructor parameter. Then the original class just contained a constructor that took the circular dependency and called the setter. The other class, Bar, depended on the parent (FooWithoutDep), and called the setter explicitly, passing itself (this
). This enables all the existing references to the class to remain the same, while still using Dagger to inject all the dependencies.
This seemed confusing enough to be worth writing up here.

- 1,720
- 1
- 13
- 35
-
I think there is a problem with this code, referring to this in Bar constructor when the object is not created, you should only refer to this after the constructor. But correct me if I'm wrong. – Saba Mar 25 '18 at 09:03
-
No, it's typical in Java to refer to `this` in constructors -- unless I'm misunderstanding what you mean... – Jesse W at Z - Given up on SE Mar 26 '18 at 16:01
-
Yes but how can you refer to this when the object is not constructed fully? I read somewhere that this is a bad practice. Another problem in this code is I think it wont let the gc to cleanup the object so remember to setBarDep(null) when you no longer need the object. – Saba Mar 27 '18 at 08:50
This is how I resolved it, without parent classes.
Class 1: Engine. (in component interface)
@Provides
public Engine myEngine(Context context) {
return new Engine (context);
}
Class 2: Parts. Engine also needs Parts instance but the creation is delayed.
@Inject
public Parts(Context context, Engine engine) {
this.context = context;
this.engine= engine;
engine.setParts(this);
}
Circular dependency can be achieved but one class must be initiated first before the other.
Again, if possible, refactor code to avoid circular DI.