Understanding cdi Instance<> and .get() vs @Inject

Christopher Poile picture Christopher Poile · Mar 26, 2012 · Viewed 15.8k times · Source

I'm a little confused about which to use in the following situation:

Suppose the servlet creates an Application that handles the user's http session, and the application is this:

public class Application extends AbstractHTTPApplication {

@Inject
private Instance<MainView> mainView;

public void setupApplication() {
   this.setView( mainView.get() );
}

Later on I have a @SessionScoped bean SSB that I want to inject into each user's bean:

@SessionScoped
public class SSB {}

Now, when I tried a regular @Inject SSB ssb; as a field in MainView, I do not get a new SSB for each user:

public class MainView {

@Inject
private SSB usersSSB;

   public someMethod() {
       usersSSB.doSomething();
       System.identityHashCode( usersSSB );
   }
}

Testing with two users, I get the same instance of usersSSB in both user's sessions. I didn't think this was possible... I thought, since SSB is SessionScoped, a new one will be given to each user session, and no matter where it is @Injected it will refer to that user's SSB.

Instead, I tried:

public class MainView {

@Inject
private Instance<SSB> usersSSB;

   public someMethod() {
       usersSSB.get().doSomething();
       System.identityHashCode( usersSSB.get() );
   }
}

Now it reports a different usersSSB for each user, finally.

What's happening here? When I call usersSSB.get() later on in each user's session, will the usersSSB.get() return that same bean for that same user each time?

I'm running on Glassfish 3.1.2.

Some More Info

The Application class is being injected into the Servlet on a new HttpServletRequest:

public abstract class AbstractCdiApplicationServlet extends
    AbstractApplicationServlet {
@Inject
protected Instance<ApplicationWrapper> wrapper;

@Override
protected Application getNewApplication(HttpServletRequest request)
        throws ServletException {
    return wrapper.get().getApplication();
}
...etc etc

And the ApplicationWrapper is a SessionScoped bean:

@SuppressWarnings("serial")
@SessionScoped
public class ApplicationWrapper implements Serializable {
@Inject
private AbstractCdiApplication application;

public AbstractCdiApplication getApplication() {
    return application;
}
 }

Doesn't this mean that calling @Inject SSB usersSSB anywhere in MainView (or any object within that user's session) should give me that user's session-scoped bean, and always that same session-scoped bean, for each user's session? Meaning -- different usersSSB for different users, because each user has a different session.

After all, the Application itself is a SessionScoped bean, injected into and attached to the user's HTTP Session by the getNewApplication method of the servlet? I mean, it is the Application object that injects and attaches the MainView class, after all, right? So that means MainView is a session-scoped bean, doesn't it?

I'm just trying to figure out how this all works, I guess. Thanks for the help!

Answer

Krzysztof Miksa picture Krzysztof Miksa · Mar 28, 2012

This happen because '@Inject Instance<>' is dynamic obtained unlike to '@Inject'

If you do '@Inject' into ApplicationScoped bean then injection is obtained only once so in ApplicationScoped bean will be this same reference for all users

If you call .get() on '@Inject Instance<>' then reference to SSB is obtained dynamically each time when you call .get()

More about injection you can read here: http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/injection.html