5 Replies Latest reply on Dec 11, 2008 2:02 PM by John Lennon

    selectItems and @Factory

    John Lennon Newbie

      Hi,


      I am trying to use annotation to initiate drop down menu on my page, unfortunately I keep getting error:


      Expected a child component type of UISelectItem/UISelectItems for component type javax.faces.SelectOne(j_id53).  Found null.



      Page source code:


      <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <ui:composition xmlns="http://www.w3.org/1999/xhtml"
          xmlns:s="http://jboss.com/products/seam/taglib"
          xmlns:ui="http://java.sun.com/jsf/facelets"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:rich="http://richfaces.org/rich"
          template="layout/template.xhtml">
      
      <ui:define name="body">
          <h:form id="search" styleClass="edit">
              <h:selectOneMenu>
               <s:selectItems
                              value="#{search.list}"/>
              </h:selectOneMenu>
          </h:form>
      </ui:define>
      </ui:composition>



      Action source code:


      import java.util.Map;
      import java.util.TreeMap;
      import org.jboss.seam.annotations.Factory;
      import org.jboss.seam.annotations.Name;
      
      @Name("search")
      public class SearchAction implements SearchLocal {
              
              Map<String,Integer> list = null;
              
              @Factory("list")
              public void initList() {
                      System.out.println("In-method initList");
                      list = new TreeMap<String,Integer>();
                      list.put("one", 1);
                      list.put("two", 2);
              }
              
              public Map<String,Integer> getList() {
                      System.out.println("In-method getList");
                      return list;
              }
      }



      Local interface source code:


      import java.util.Map;
      import javax.ejb.Local;
      
      @Local
      public interface SearchLocal {          
              public Map<String,Integer> getList();     
              public void initList();
      }

        • 1. Re: selectItems and @Factory
          asaf sh Expert

          Factory method (initList) is never invoked,


          Factory annotation recieves as a parameter a seam component, not a method/property of a component.


          @Create makes more sense here.


          Asaf.

          • 2. Re: selectItems and @Factory
            John Lennon Newbie

            Thank you, @Create works fine :)


            Here is fixed version of code which initializes list variable correctly:


            import java.util.Map;
            import java.util.TreeMap;
            import org.jboss.seam.annotations.Create;
            import org.jboss.seam.annotations.Name;
            
            @Name("search")
            public class SearchAction implements SearchLocal {
            
                 Map<String,Integer> list = null;
                 
                 @Create
                 public void initList() {
                      System.out.println("In-method initList");
                      list = new TreeMap<String,Integer>();
                      list.put("one", 1);
                      list.put("two", 2);
                 }
                      
                 public Map<String,Integer> getList() {
                      System.out.println("In-method getList");
                      return list;
                 }
            }



            I still have question: where can I use @Factory? In seam documentation describing @Factory  I don't fully understand examples:



            1. fist style - here I'm confused, I thought that my example should work like this but it's not, what is the difference? is it because my one is not in CONVERSATION context?

            2. second style - here I understand that @Factory is bounded with context variable customerList which is outjected using @DataModel and whenever this variable is requested from the page it is initiated - is it correct?

            • 4. Re: selectItems and @Factory
              John Lennon Newbie

              It looks like brilliant source of information :) Thank you very much !

              • 5. Re: selectItems and @Factory
                John Lennon Newbie

                Thank you for link, here are 3 possible examples how to initialize component:


                1. Using @Unwrap with method returning object - method doesn't have to be getter:


                @Name("search")
                public class SearchAction {
                     
                     // can't be used with @Out
                     @Unwrap
                     public Map<String,Integer> initList() {
                          System.out.println("In-method initList");
                          Map<String,Integer> list = new TreeMap<String,Integer>();
                          list.put("one", 1);
                          list.put("two", 2);
                          list.put("three", 3);
                          return list;
                     }
                }



                to use this component on the page you need to call it search:


                <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                    xmlns:s="http://jboss.com/products/seam/taglib"
                    xmlns:ui="http://java.sun.com/jsf/facelets"
                    xmlns:f="http://java.sun.com/jsf/core"
                    xmlns:h="http://java.sun.com/jsf/html"
                    xmlns:rich="http://richfaces.org/rich"
                    template="layout/template.xhtml">
                
                <ui:define name="body">
                    <h:form id="search" styleClass="edit">
                        <h:selectOneMenu>
                         <s:selectItems
                                  value="#{search}"/>
                        </h:selectOneMenu>
                    </h:form>
                </ui:define>
                </ui:composition>



                2. Using @Factory with method returning void - method doesn't have to be getter and @Out must be used to outject object to page:


                @Name("search")
                public class SearchAction {
                     
                     // use with @Out because creation method is returning void     
                     @Out
                     private Map<String,Integer> list;
                     
                     @Factory("list")
                     public void initList() {
                          System.out.println("In-method initList");
                          list = new TreeMap<String,Integer>();
                          list.put("one", 1);
                          list.put("two", 2);
                          list.put("three", 3);
                          list.put("six", 6);
                     }
                }



                to use this component on the page you need to call it list:


                <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                    xmlns:s="http://jboss.com/products/seam/taglib"
                    xmlns:ui="http://java.sun.com/jsf/facelets"
                    xmlns:f="http://java.sun.com/jsf/core"
                    xmlns:h="http://java.sun.com/jsf/html"
                    xmlns:rich="http://richfaces.org/rich"
                    template="layout/template.xhtml">
                
                <ui:define name="body">
                    <h:form id="search" styleClass="edit">
                        <h:selectOneMenu>
                         <s:selectItems
                                  value="#{list}"/>
                        </h:selectOneMenu>
                    </h:form>
                </ui:define>
                </ui:composition>



                3. Using @Factory with method returning object - method mut be getter, @Out is not needed


                @Name("search")
                public class SearchAction {
                     // without @Out annotation
                     @Factory("list")
                     public Map<String,Integer> getList() {
                          System.out.println("In-method initList");
                          Map<String,Integer> list = new TreeMap<String,Integer>();
                          list.put("one", 1);
                          list.put("two", 2);
                          list.put("three", 3);          
                          return list;
                     }
                }



                component usage is like in example (2.)


                Additionally class used in all these examples doesn't have to be EJB bean - they only have to be Seam component (marked by @Name annotation).


                Each of these method is different - details can be found in http://chiralsoftware.com/jboss-seam-book/unwrap.seam as previously mentioned Thiago Rocha (thanks).