Why stateless beans are treated as pseudo-scoped and cannot have circular dependencies?
Asked Answered
C

3

9

Using Wildfly 8.1 I have several beans which I try to inject several EJB into each other. Lets say I have 3 beans:

@Stateless 
public class A{
  @Inject
  private B b;
}

@Stateless 
public class B{
  @Inject
  private C c;
}

@Stateless 
public class C{
  @Inject
  private A a;
}

Obviously, I have circular dependency. According to specification:

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

Running above code in container result in an error of the form:

org.jboss.weld.exceptions.DeploymentException: WELD-001443: Pseudo scoped bean has circular dependencies. Dependency path:

-Session bean [class A with qualifiers [@Default @Any]; local interfaces are [A] BackedAnnotatedField] @Inject private B,

[..]

My question here is: what is the scope of @Stateless beans? Is it by default @Dependent? And most of all how can I enable circular dependencies between stateless session beans?

Sorry if the question is too trivial. I will appreciate any good further reading sources which will explain presented behavior. Thanks in advance.

UPDATED Ok. I found the workaround. I've used @EJB annotation instead of @Inject but this does not explain the weird behavior of @Inject. The question remains open but as Mika suggested it may be unresolved issue in both CDI specification and Weld RI.

Chimene answered 20/10, 2014 at 14:5 Comment(6)
I don't have an answer, but it's not a trivial question. There was a discussion about this between the CDI EG members. Look at the CDI spec jira, there should be an issue about this very topic.Luncheon
@MikeBraun could you perhaps provide a link to the jira issue? I've searched but I'm not sure I'm looking at the right one.Chimene
it's CDI-414, see issues.jboss.org/browse/CDI-414Luncheon
Thanks. As it's written in description current workaround is same as I've put in update. So for now I'll make it an answer.Chimene
CDI-414 deals with self injection, not circular injection.Smythe
@johnAment I know, but CDI sees the same circular dependency in that case, and like in that case it's resolved using the '@EJB' annotation. This means it's not a technical limitation, but just the fact that CDI doesn't see the Stateless "scope" for what it really is.Luncheon
C
9

It's a bug in wildfly/jboss CDI implementation. Current workaround (as suggested by @MikeBraun), provided in issue description https://issues.jboss.org/browse/CDI-414, is to use @EJB annotation instead of @Inject.

Chimene answered 3/11, 2014 at 16:33 Comment(0)
S
3

@Stateless has no scope and has no correlation to any scope. Your beans are ending up as @Dependent since you have not annotated any other scope on your beans.

You need to give them a normal scope - @RequestScoped or @ApplicationScoped, however I'm not sure either makes sense in your case.

Smythe answered 20/10, 2014 at 19:50 Comment(2)
Your solution will only be valid if it was managed been within the web layer. As it is EJB bean it is rather a bug inside CDI implementation.Chimene
I don't agree with this. Scoping Stateless makes no sense here and I think it would not even work. Only Stateful beans can have scopes. The fact is that CDI hasn't got a really convincing answer for the phenomenon that is '@Stateless'. A stateless bean is more like an endpoint listening to messages, than a regular bean. That's why self injection and circular dependencies are no issues. A stateless proxy is more like a URL. When a method call happens, it's send to any bean of that type (a new instance, one from a pool, always the same one, ...). So request scoped would be utterly wrong here.Luncheon
U
3

This doesn't answer the entire question, but it was the first hit on google when I searched circular dependency exceptions. Hoping this will help other programmers finding a quicker answer here is my solution.

The code that cause circular dependency exception:

class A{
    @Inject B b;
    public void foo(){
        b.bar();
    }
    public void quux(){
        //some code
    }
}
class B{
    @Inject A a;
    public void bar(){
        //some code
    }
    public void baz(){
        a.quux();
    }
}

A solution to solve the issue is by using javax.enterprise.inject.Instance

class A{
    @Inject B b;
    public void foo(){
        b.bar();
    }
    public void quux(){
        //some code
    }
}
class B{
    @Inject Instance<A> a;
    public void bar(){
        //some code
    }
    public void baz(){
        a.get().quux();
    }
}
Udela answered 8/12, 2015 at 19:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.