1

I have two beans using @Named, one with @SessionScoped and the other one with @ViewScoped. I can inject the @ViewScoped bean into the @SessionScoped and I try to do the opposite, and I almost works, but I don't have the same instances.

I can see it when I print this.hashCode() inside the @PostContruct method of the view scoped bean and compare it to the one injected inside the session scoped bean.

So I found a solution but I don't know if it is a good practice: inside the @PostContruct method of the view scoped bean after the session scoped bean has been injected, I send the view scoped into the session scoped through a setter.

If I have well understood these objects are tied to the user so it doesn't make any trouble, am I right?

@Named
@ViewScoped
public class ViewScopedBean {

    @Inject
    protected SessionScopedBean sessionScopedBean;

    @PostContruct
    public void init() {

        sessionScopedBean.setViewScopedBean(this);
    }
}

@Named
@SessionScoped
public class SessionScopedBean {

    protected ViewScopedBean viewScopedBean;

    public void setViewScopedBean(ViewScopedBean viewScopedBean) {

        this.viewScopedBean = viewScopedBean;
    }
}
Jens Piegsa
  • 7,399
  • 5
  • 58
  • 106
kaizokun
  • 926
  • 3
  • 9
  • 31
  • Two things to note here. Firstly, are those 2 view scoped beans you are getting actually different? Remember that they are (most likely) proxies, so verify it using their internal state rather than `hashCode` (which could be invoked at proxy level). Secondly - are you sure you understand `ViewScoped` lifecycle well enough? E.g. it may be logical that you get two different instances because it's bound to JSF view. See also [this answer](https://stackoverflow.com/questions/6025998/difference-between-view-and-request-scope-in-managed-beans/) – Siliarus Feb 26 '18 at 09:02
  • Thank you for you answer, you're right ! I checked and it is the same object embedded in a proxy. If I call the hashcode on the Injected ViewScopedBean I see the proxy's one, but if I call a method of the embedded bean ( that print hashcode to ) I can see it's the same. About the livecycle I think so but I don't know all the details ( I should ^^), I use a ViewScoped Bean to keep the state of a primefaces tree component, the nodes can be expanded using lazy loading. – kaizokun Feb 26 '18 at 10:36
  • With the old ManagedBean system I couldn' t inject a viewScopedBean into a sessionScopedBean with the @ManagedProperty annotation. But here I'm curious to know how it works. I guess any time the ViewScopedBean change it is re-injected into the SessionScopedBean, is that right ? – kaizokun Feb 26 '18 at 10:36
  • I am not familiar with implementation details of view scoped, but from CDI perspective (view scoped comes from JSF) you should always be injecting the currenctly active (if any) view scoped bean in given context and thread. The creation/replacement of that underlying view scoped bean is mandated by JSF impl and should happen upon creating/exiting view. – Siliarus Feb 26 '18 at 11:28
  • I have extracted the comment into an answer, so that this SO question can be resolved. – Siliarus Feb 26 '18 at 11:34

2 Answers2

0

Extracting what I wrote in comments into an answer:

The catch here was that CDI/Weld doesn't @Inject a contextual instance directly but rather hands over proxy instances (for @NormalScoped beans!), which then delegate to one underlying instance of a bean; in this case @ViewScoped bean.

In the question the assumption was made that hashCode() can be used on injected object(s) to verify that they are identical. That, however, does not need to be true as CDI can choose to give you a different proxy for each injection point and hashCode() will be invoked on the proxy object, not the underlying bean instance - hence the differences.

Way to go is checking bean's internal state, which proved to be equal therefore showing that both injection points have injected the same instance of @viewScoped bean.

Siliarus
  • 6,393
  • 1
  • 14
  • 30
  • If the `hashCode()` method was implemented on the proxied object, the proxy object will call the `hashCode()` Method of the proxied Object... The same goes for `equals()` – thobens Feb 26 '18 at 15:19
  • The `hashCode` (and by extension `equals`) are most likely implemented there (you can dump bytecode of proxies easily in weld and check) and that is why this behaviour happens. Different proxies are delivered to two different IPs. – Siliarus Feb 26 '18 at 15:28
0

I see two problems:

  1. Your main problem here is that you have circular dependencies. Try to avoid that. The ViewScopedBean cannot depend on the SessionScopedBean and vice versa, because CDI won't know wich one to create first. (That's why you have to set your dependency manually in the @PostConstruct method.)
  2. You can't compare Beans by comparing their references, since they get serialized / unserialized and thus are not the same objects. This is why you should compare them using equals() and implement the hashCode() methods.
thobens
  • 1,729
  • 1
  • 15
  • 34
  • CDI can handle certain amount of circular dependencies by default thanks to it's lazy initiation (at least in Weld) and proxies. But from what I understood, OP introduced this dependency only to verify the injection behaviour? But you've got a point there. As for 2. - again, this is Weld impl detail, but you can see how these are created for client proxies [here](https://github.com/weld/core/blob/master/impl/src/main/java/org/jboss/weld/bean/proxy/ClientProxyFactory.java#L257-L282). Read the javadoc to understand how precisely this works, your answer is misleading and won't hold true. – Siliarus Feb 26 '18 at 15:44
  • @thobens thanks, I'm not sure but I think that a sessionScopedBean can be injected into a viewScopedBean because the sessionScopedBean is created first because it is tied to the user session and the viewScopedBean must be created then when a specific view is called.And it seems to handle the circular dependency pretty well. – kaizokun Feb 26 '18 at 16:31
  • anyway if I want to do it manually into the @PostConstruct and avoid the circular dependencies I must at least inject one of them :p. And thanks for the information about the serialization, I've forgotten ! – kaizokun Feb 26 '18 at 16:37