10

I have situation like this. I cannot see any errors but I am not getting my results.

@ApplicationScoped
public class A {

    private B b;


    @Inject
    public A(B b) {
        this.b = b;
    }
}

@Singleton
public class B {

    private A a;


    @Inject
    public B(A a) {
        this.a = a;
    }
}

Is this type of dependency injection is wrong?

Can any one help me with this.

Patan
  • 17,073
  • 36
  • 124
  • 198
  • You need to refactor, move the the dependent code away from these A and B classes, and create a C class. – André Apr 27 '15 at 14:10
  • @André. Thanks for the reply. Can you tell how this A and B called from C – Patan Apr 27 '15 at 14:12
  • CDI cannot handle circular dependency, EJB can – maress Apr 27 '15 at 14:12
  • 2
    @maress, yeah it can, but I think it's a code smell, having circular dependency. Either he can refactor or start using EJB. – André Apr 27 '15 at 14:15
  • 1
    You don't mention your environment. Weld 2.2.11.Final gives me a very clear error message: `WELD-001410: The injection point [BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] @Inject public demo.B(A) has non-proxyable dependencies` – Harald Wellmann Apr 27 '15 at 18:36

4 Answers4

5

I'd avoid this circular dependency, there is a few reasons to do that.

Comment on this article

A messy constructor is a sign. It warns me that my class is becoming a monolith which is a jack of all trades and a master of none. In other words, a messy constructor is actually a good thing. If I feel that the constructor of a class is too messy, I know that it is time to do something about it.

And this one

You’ll find cases where a class A needs an instance of B and B needs an instance of A. This is a typical case of a circular dependency and is obviously bad. In my experience the solution is either to make B a part of A when the two are so strongly dependent that they really should be one class. More often though there is at least one more class C hiding in there so that B doesn’t need A but only C.

As Oliver Gerke commented:

Especially constructor injection actually prevents you from introducing cyclic dependencies. If you do introduce them you essentially make the two parties one because you cannot really change the one without risking to break the other, which in every case is a design smell.

Here is a small example of what I might do.

public class A {

    private B b;

    @Autowired
    public A(B b) {
        this.b = b;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithB() {
        b.doSomeWork();
    }
}

public class B {

    private A a;

    @Autowired
    public B(A a) {
        this.a = a;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithA() {
        a.doSomeWork();
    }

}

After refactoring it might look like this.

public class A {

    private C c;

    @Autowired
    public A(C c) {
        this.c = c;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithC() {
        c.doSomeWorkThatWasOnA();
    }

}

public class B {

    private C c;

    @Autowired
    public B(C c) {
        this.c = c;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithC() {
        c.doSomeWorkThatWasOnB();
    }

}

public class C {

    public void doSomeWorkThatWasOnB() {
        // WORK

    }

    public void doSomeWorkThatWasOnA() {
        // WORK
    }

}
André
  • 2,184
  • 1
  • 22
  • 30
  • 1
    There is a lot of reading that you can do on the links I posted, happy reading and coding! :D – André Apr 27 '15 at 14:39
  • Thank you very much. Can you tell how would I call some method from C. Or shall I have to copy all the logic there? – Patan Apr 27 '15 at 15:34
  • You refactor the code from A and B so there is no call from A to B and B to A, moving the logic to C – André Apr 27 '15 at 16:08
  • The question is about CDI, not about Spring or dependency injection in general. I do agree that cyclic dependencies should be avoided, but your answer does not really address the question. – Harald Wellmann Apr 27 '15 at 18:31
  • Thank you for your input @hwellmann, I will look into CDI and delete the answer if I reach the same conclusion – André Apr 27 '15 at 19:05
  • I did misread the `@Inject` for `@Autowired` and Spring, but still, reading this answer http://stackoverflow.com/questions/15300338/cdi-injection-loop/15301179#15301179 does validate my suggestion of refactoring. Right you are that doesn't answer the issue of the missing constructor, but I feel this is also a proper answer as well. – André Apr 27 '15 at 19:32
5

Quoting from Section 5 of the CDI Specification 1.2:

The container is required to support circularities in the bean dependency graph where at least one bean participating in every circular chain of dependencies has a normal scope, as defined in Normal scopes and pseudo-scopes. The container is not required to support circular chains of dependencies where every bean participating in the chain has a pseudo-scope.

ApplicationScoped is a normal scope, so this cycle should work.

In your sample, class A cannot be proxied since it's missing a zero-argument constructor. Adding this constructor (which may have protected or package visibility), your sample deploys without problems.

Harald Wellmann
  • 12,615
  • 4
  • 41
  • 63
  • This correctly solves the issue, if class `A` is missing it's no-arg constructor on Patan's source. – André Apr 27 '15 at 19:34
1

You can also use Setter based Dependency Injection to resolve this issue.

Sunil Rajashekar
  • 350
  • 2
  • 18
  • If you have dependency Injection through constructor, ClassA needs ClassB and ClassB needs ClassA to be instantiated this creates a circular dependency. If you use setter based DI, Either classA or ClassB is instantiated first, later the instantiated objects are used to set Property of one another which breaks the cyclic dependency. – Sunil Rajashekar Apr 27 '15 at 16:03
  • I'd like to expand this answer a bit, because I've found it useful. You can use @PostConstruct, to set your dependency manually using a setter, so you can have a setter based depedency injection – Vokail Oct 19 '20 at 14:50
1

There is definitely a solution to this. Let me quote myself:

The right solution is to inject javax.enterprise.inject.Instance, where T is type of the class to be injected. Since the type is directly Foo, calling get() method on an object typed as Instance is guaranteed to inject the right object all the time. This approach works very well, because the instance is obtained dynamically from the container by the implementation itself and only as needed. Therefore, the responsibility of dependency retrieval is left to your code - your code is responsible not to make an endless loop.

 @Named
public class Foo implements Fooable{

@Inject
private Instance<Foo> foo;

public void executeFirst(){
foo.get().executeSecond();
}

@Transactional
public void executeSecond(){
//do something
}

}