11 Replies Latest reply on Jun 16, 2006 1:25 AM by gavin.king

    Injected value is always null

    georgesberscheid

      I'm trying to write a simple CRUD application using Seam. I'm displaying a list of users in a dataTable (using @DataModel, @DataModelSelection and @Factory), each of which has an 'Edit' button to edit the user's data in a different form. The form looks like this:

      <h:inputText id="lastname" value="#{user.lastname}"></h:inputText>
      <h:inputText id="firstname" value="#{user.firstname}"></h:inputText>
      <h:commandButton id="submit" value="Edit" action="#{userManager.edit}" />


      The managed bean has @In and @Out annotations on the setter and getter of the user variable.

      protected User user;
      
      @In("user")
      public void setUser(User user) {this.user = user; }
      
      @Out("user")
      public User getUser() {return this.user; }
      


      After selecting a user from the dataTable, its existing properties are displayed correctly in the edit form. However, if the edit form is submitted, the <h:message> tags display the following error: "firstname": Error during model data update.

      Before the userManager.edit() method is called, the value of user is injected by calling the setUser() method.
      Unfortunately the parameter passed to setUser() is always null and I can't figure out why.
      I see the same behavior if I use the @In and @Out annotations directly on the instance variable instead of the getter/setter methods.

      Any ideas?

      (To be precise, userManager.edit() is never called, because the properties can never be set on the injected null object. Hance, the update model phase fails and the invoke application phase is never reached.)

        • 1. Re: Injected value is always null
          gavin.king

          Does the User class have an @Name("user") annotation?

          • 2. Re: Injected value is always null
            georgesberscheid

            Wow, thanks for that super-quick reply.

            Hmmm, that's gotta be the problem. User (entity bean) doesn't have a @Name annotation because it's included in an EJB-JAR from a different application.
            Is there any other way to make Seam inject an instance of that class without having to recompile my entity bean?
            Could I for instance create a sub-class of User (let's call it UserSeam), and annotate it with @Name. Would it still be an entity bean, or would I have to re-insert all the annotations (like @Table, @Id, @OneToMany etc.) from User into UserSeam?

            • 3. Re: Injected value is always null
              georgesberscheid

              One could for example make the @Name, @Role and @Roles annotations available inside a Seam component (which is scanned anyway at deployment time) by allowing ElementType for the annotations to be FIELD or METHOD as well.
              That way, the Seam interceptor would know which instances to inject into which Seam component before one of its methods is invoked.

              Example:

              @Name("userManager")
              @Interceptors(SeamInterceptor.class)
              public class UserManagerBean {
               @Name("user")
               @In
               protected User user;
              
               public void add() {
               // Add the injected user into the database
               }
              }
              


              Would that make sense?

              • 4. Re: Injected value is always null
                max522over

                maybe I'm misunderstanding you but the docs say

                @In(value="contextVariableName", create=false, required=false)


                so why couldn't you just say

                @In(value="user")




                • 5. Re: Injected value is always null
                  georgesberscheid

                  Yes, that will only work if you have previously annotated the User class with @Name and made it a Seam component.
                  Assume you have an existing JEE application with lots of entity beans that you would like to use to create a new web-frontend for that application. You wouldn't want to recompile all the entity bean classes and add a @Name annotation to use them with Seam, right?

                  So I was suggesting to allow injection of any Java bean. It does work with @Out, so why shouldn't it work with @In?

                  • 6. Re: Injected value is always null
                    max522over

                    ok, I think I understand better what you mean. I had three responses to you comments.

                    1. I don't mind recompiling one bit. I've been using Continuous integration for several years on all my projects (I'm involved in 13 currently) and I recompile my application and run unit test on them every hour on the hour. On the Seam project I started 4 weeks ago we changed CI to recompile every 5 minutes if a change in subversion has occurred.

                    2. I could maybe see not adding the annotation or wanting to use components written in java 1.4 and reusing them in a 1.5 application but not wanting to change the source code, just reuse them out of a jar. So I could see a need for putting objects in contextual state that are not annotated or can not be annotated with @Name.

                    3. I think the @Out annotation solves this problem better than adding @Name at the instance variable or method level. If I can fundamentally change the nature of a class in another class, then the two classes have a level of coupling I'm not excited about. To me, that is what @Name for a class that I reference in my class would do. But I can accomplish the same thing with the @Out but that is limited to the influece of the class doing the @Out and @Factory is an important part of that decoupling.

                    Those are just thoughts as I think about what you are saying. I'm certain I haven't thought of everything or maybe there is more reasons. I'm open to comment. I appreciate this dialog, it's making me think about the nature of Seam's subversion.

                    It just sort of opens the door for all kinds of wild data injections and begins to erode encapsulation. At least that is what I'm beginning to see that possibility with the team I'm working with who is using Seam. I'm not sure how to direct the team to improve that.

                    • 7. Re: Injected value is always null
                      gavin.king

                       

                      "georgesberscheid" wrote:

                      Is there any other way to make Seam inject an instance of that class without having to recompile my entity bean?
                      Could I for instance create a sub-class of User (let's call it UserSeam), and annotate it with @Name. Would it still be an entity bean, or would I have to re-insert all the annotations (like @Table, @Id, @OneToMany etc.) from User into UserSeam?


                      Use the manager component pattern. ie. write a Seam component with an @Unwrap method that returns the User.

                      Or, if all you need is instantiation, you could even use an @Factory method.

                      • 8. Re: Injected value is always null
                        tom.serru

                        We have the same problem since we moved to version 1.0.0.CR3 of seam and the 4.0.4 GA JBoss version. We used the injection and outjection with version 4.0.4 RC2 of JBoss and Seam 1.0.beta2 and everything worked perfect.

                        I have three beans. One bean to store session data (session scope), one general application bean wich stores some constants and application information (request scope) and one message center bean (session scope).

                        Session bean:

                        @Out(value="locale", scope=ScopeType.SESSION)
                        private Locale locale = new Locale("en", "", "");

                        General bean:

                        @Out(value="filetypes", scope=ScopeType.SESSION)
                        private List filetypes = new ArrayList();

                        Message center bean:

                        @In(value = "locale", required = true, scope = ScopeType.SESSION)
                        private Locale locale;
                        @In(value = "filetypes", required = true, scope = ScopeType.SESSION)
                        private List knownFileTypes;

                        The current locale is stored in the session bean and passed to the message center bean with injection. The same for the known file types that are stored in the general application bean. Since the upgrade it's not working anymore, and we get null values.

                        • 9. Re: Injected value is always null
                          gavin.king

                          I don't understand how this is "the same problem" as anything else discussed in this thread...?

                          And I'm not sure what you are trying to say.... that @Out(scope=SESSION) is broken? This seems very unlikely...

                          By the way, given defaulting, etc, you can write the above code simply as:

                          @Out(scope=ScopeType.SESSION)
                          private Locale locale = new Locale("en", "", "");

                          @Out(scope=ScopeType.SESSION)
                          private List filetypes = new ArrayList();

                          @In
                          private Locale locale;
                          @In(value = "filetypes")
                          private List knownFileTypes;

                          • 10. Re: Injected value is always null
                            dhinojosa

                            Ehhhh. I think I figured it out!!!!

                            You need to make sure that the param-value for the jndipattern in your web.xml is set to the correct JNDI tree set up.

                            <context-param>
                            <param-name>org.jboss.seam.core.init.jndiPattern</param-name>
                            <param-value>PUT YOUR PERSISTENCE CONTEXT HERE!!!!!!!/#{ejbName}/local</param-value>
                            </context-param>

                            If you don't know what your jndi looks like then look here http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&name=jboss%3Aservice%3DJNDIView

                            and click on list invoke.

                            • 11. Re: Injected value is always null
                              gavin.king

                              Right, the correct pattern is:

                              myEarName/#{ejbName}/local