I'm getting the following error in my code at launch:
Tried proxying com.bar.Foo to support a circular dependency, but it is not an interface.
How exactly does this proxying work? If I just throw enough classes behind interfaces, will everything be fine?
(I know that circular dependencies are usually a code smell, but I think in this case it's ok.)
While the "inject an interface" approach is totally valid, and might even be the better solution in some occasions, in general, you can use a simpler solution: Providers.
For every class "A" guice can manage, guice also offers a "
Provider<A>
". This is an internal implementation of the javax.inject.Provider-interface, whoseget()
message will "return injector.getInstance(A.class)
". You dont have to implement the Interface yourself, its part of the "guice magic".Thus you can shorten the A->B, B-A example to:
I prefer this, because its more readable (you are not fooled to beleive that the constructor already holds an instance of "B") and since you could implement the Providers yourself, it would still work "by Hand", outside the guice context (for testing for example).
Here is @jan-galinski's answer, redone in Scala:
I'm new to this concept, but here's my understanding.
Let's say you have interfaces
A
andB
, and implementationsAi
andBi
.If
Ai
has a dependency onB
, andBi
has a dependency onA
, then Guice can create a proxy implementation ofA
(call itAp
) that will at some point in the future be given anAi
to delegate to. Guice gives thatAp
toBi
for its dependency onA
, allowingBi
to finish instantiation. Then, sinceBi
has been instantiated, Guice can instantiateAi
withBi
. Then, sinceAi
is now good to do, Guice tellsAp
to delegate toAi
.If
A
andB
were not interfaces (and you just hadAi
andBi
) this just would not be possible, because creatingAp
would require you to extendAi
, which already needs aBi
.Here's what it might look like with code:
The proxy class that Guice makes would look like this:
And it would all be wired using this basic idea:
And here's what it would be like if you only had
Ai
andBi
, without interfacesA
andB
.I would guess that there are strict restrictions on how the proxy can be interacted with in the constructor. In other words, if B tries to call A before Guice has had a chance to populate A's proxy with the real A, then I would expect a RuntimeException.