3 Replies Latest reply on Jan 20, 2010 2:18 AM by Tim Evers

    Referencing components from other components

    Brian Johnson Newbie

      So, I'm attempting to do something which I think should work, but doesn't.  I'm going to post a way oversimplified version of what I'm doing.  I'm questioning my fundamental understanding of Seam.  What I'm looking for by way of response is:
      a) Yes, Brian, what you've written there should work.  Something that you've left out must be breaking it
      OR
      b) No, Brian, you don't get Seam at all.


      Given the following code:


      @Name("authenticator")
      public class AuthenticatorAction extends SeamLoginModule implements Authenticator
      {
          @Out(required=false)
          private WebUser webUser;
      
          public boolean authenticate()
          {
              //do some authentication stuff
              webUser = new WebUser();
              webUser.setUserDataOne("one");
              webUser.setUserDataTwo("two");
          }
      }
      



      And the following def of WebUser


      @Name("webUser")
      @Scope(ScopeType.SESSION)
      public class WebUser implements Serializable
      {
          private String userDataOne;
          private String userDataTwo;
      
          public WebUser()
          {
              this.userDateOne = "initone";
              this.userDataTwo = "inittwo";
          }
      }
      



      Assume the proper getters/setters for userDataOne and userDataTwo (I'll omit them to save space)


      I've got another component, we'll call it myThing.  It'll be instantiated by a reference in an .xhtml page.  (like some tag with value=#{myThing.somevalue} )
      Obviously, the myThing reference won't be made until after the authenticate function has run.
      myThing defined as:


      @Name("myThing")
      @Scope(ScopeType.SESSION)
      public class MyThingBean implements Serializable
      
          @In
          private WebUser webUser;
      
          public MyThingBean()
          {
              String myString = webUser.getUserDataOne;
          }
      }
      



      When I get into the constructor of MyThingBean, because it has been referenced by the xhtml file, webUser is null. 


      I'm sure that webUser gets instantiated by the authenticate method.  Also, the @In annotation on webUser in MyThingBean doesn't have required=false, so why doesn't that cause the code to blow up when webUser is null?  Instead I get a NPE in the constructor when I try to access a member of webUser.


      I am allowed to access a component like that from within a backing bean, right?  Elsewhere in my app I've got actions that access components via the @In annotation just fine, but when I try to do it from inside a backing bean it never seems to work.


      Thanks in advance.

        • 1. Re: Referencing components from other components
          Tim Evers Master

          The problem here is that you are doing work in the constructor. When a Seam bean is instantiated Seam will make a proxy around the instance. Thus at the time of object instantiation the @In has not occured.


          Try moving your code to another method that looks like this.


          @Create
          public void doMyThing() {
              String myString = webUser.getUserDataOne();
          }
          



          This method will now get called after the Seam bean has been created (properly). Thus the Injection should work and you should no longer get the NPE.


          How seam creates and works with beans is something that is a good idea to get to understand. Basically... don't do stuff in constructors. And never create a Seam bean by doing SeamBean x = new SeamBean();


          Hope this helps.

          • 2. Re: Referencing components from other components
            Brian Johnson Newbie

            Thanks for your reply.  Instead of doing


            SeamBean x = new SeamBean();


            should I be doing:


            SeamBean x = Component.getInstance(seamBean);


            or something else?

            • 3. Re: Referencing components from other components
              Tim Evers Master

              Yes, if you want to get access to a Seam bean without using @In then use the Component.getInstance to get it.


              Generally speaking the @In annotation is sufficient. But there are most certainly circumstances in which it does not work.


              Infact I have a JIRA in the queue at the moment for one of the scenarios in which @In does not work.


              If SeamBeanA calls SeamBeanB and SeamBeanB @Ins SeamBeanA and calls a method on it. Then when execution finishes in SeamBeanB and control returns to SeamBeanA all of SeamBeanA's injected variables will be null.


              In this scenario using Component.getInstance is useful.