5 Replies Latest reply on Jul 30, 2010 8:47 AM by wangliyu

    Is it possible to inject a session scoped bean optionally?

    ruimo.ruimo.ruimo.com

      Hi, is there a way to inject a session scoped bean optionally? For example, there is a session scoped bean that manages login session.



      @Named @SessionScoped
      public class LoginSession implements Serializable {
      ...
      }


      If you inject this bean into another request scoped bean,



      @Named @RequestScoped
      public class LoginService {
          @Inject LoginSession loginSession;
      }


      It always creates instance of LoginSession. It means session is always created even if the user is not logged in. I tried to use javax.enterprise.inject.Instance in vain.



      @Named @RequestScoped
      public class LoginService {
          @Inject Instance<LoginSession> loginSessionFactory;
      }


      If you call loginSessionFactory.get(), it always creates the instance of the LoginSession. I want something like loginSessionFactory.get(false) and it returns non-null value if and only if there is an instance in session scope otherwise null.

        • 1. Re: Is it possible to inject a session scoped bean optionally?
          nickarls

          Not exactly. Perhaps you can use some combination of a flag and a producer method?

          • 2. Re: Is it possible to inject a session scoped bean optionally?
            ruimo.ruimo.ruimo.com

            Thank you for your reply. I eventually gave up to use @SessionScoped and have created the following producer method.




                @RequestScoped @Produces LoginSession factory() {
                    HttpSession hs = (HttpSession)context.getSession(false);
                    if (hs == null) return LoginSession.NULL;
                    
                    try {
                        return (LoginSession)hs.getAttribute(LoginSession.KEY);
                    }
                    catch (IllegalStateException e) {
                        return LoginSession.NULL;
                    }
                }
            



            Where LoginSession is a class that holds login information:


            @Named @RequestScoped
            public class LoginSession implements Serializable {
                public static final LoginSession NULL = new Null();
            
                static class Null extends LoginSession {
                    private static final long serialVersionUID = -8378908668473484687L;
                    Null() {
                        super (-1L);
                    }
                    @Override public boolean isLogined() {return false;}
                    @Override public long getLoginId() {
                        throw new IllegalStateException("User is not logged in.");
                    }
                }
            
                final long loginId;
            
                public LoginSession(long loginId) {
                    this.loginId = loginId;
                }
                public boolean isLogined() {return true;}
                public long getLoginId() {return loginId;}
            }
            



            But WELD complains the following:






            org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001400 Normal scoped bean org.jboss.weld.bean-flat-ProducerMethod-gojira.web.Session.method factory() is not proxyable


            Any suggestions will be appreciated.

            • 3. Re: Is it possible to inject a session scoped bean optionally?
              ruimo.ruimo.ruimo.com

              Solved. I changed the scope of the class that declars factory() method to dependent. Then let the Null class to normal top-level request scoped bean.
              Anyway, IMO, @SessionScoped seems to be not very convenient.

              • 4. Re: Is it possible to inject a session scoped bean optionally?
                wangliyu

                I found the same issue, here is a workaround:


                @Named
                @SessionScoped
                public class LoginSession implement Serializable {
                   private User user;
                  
                   public void login() {}


                   @Produces
                   @RequestScoped
                   public User getUser() {}


                   @Predestroy
                   public void logout() {}


                   // called when request scope destroyed.
                   public void disposeUser(@Disposed User user) {}
                }


                In other small scope you can just use:


                @RequestScoped
                @Named
                public class someService {
                  @Inject private User user;
                ...
                }


                this works

                • 5. Re: Is it possible to inject a session scoped bean optionally?
                  wangliyu
                  Actually I'm thinking to use @Produces can do this,


                  @Produces
                  @SessionScoped
                  public LoginSession getLoginSession() {
                      if (ExternalContext.getSession(false) == null)
                          return null;
                      return new LoginSession();
                  }

                  but seems the getSession method always return not null.