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

    selectItems and @Factory

      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
          trouby

          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

            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?

            • 3. Re: selectItems and @Factory
              thiagorocha
              • 4. Re: selectItems and @Factory

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

                • 5. Re: selectItems and @Factory

                  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).