7 Replies Latest reply on Oct 23, 2007 11:40 AM by Blue

    SelectOneMenu and OneToMany Seam 2.0 setup

    Blue Newbie

      Hey Everyone,

      I have a simple two table database (Person and ZipCode) that have a relationship on the zipcode id (OneToMany)...I want a SelectOneMenu to display the zipcodes and when I click on an add button, I want the correct dropdown item to be persisted to the database.

      I have searched in this forum for the answer but I have got so many different solution with only parts of the code display that I don't know which one to use...I even went to the wiki where I found something that looked promising:

      http://wiki.jboss.org/wiki/Wiki.jsp?page=SeamEntityConverter

      Only to read that, that certain article was on of date:

      http://jboss.com/index.html?module=bb&op=viewtopic&t=120134

      So I'm looking for the latest technique in dealing with the above issue...If you can point me to an updated reference or even be so kind to post your full code that works with the latest Snapshot of Seam...Thank you.

      Blue

        • 1. Re: SelectOneMenu and OneToMany Seam 2.0 setup
          Blue Newbie

          Here is what I have so far:

          Here is my xhtml file:

          
          <!DOCTYPE html 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:ui="http://java.sun.com/jsf/facelets"
           xmlns:h="http://java.sun.com/jsf/html"
           xmlns:f="http://java.sun.com/jsf/core"
           xmlns:s="http://jboss.com/products/seam/taglib"
           xmlns:a4j="http://richfaces.org/a4j"
           xmlns:rich="http://richfaces.org/rich"
           template="template.xhtml">
          
          <!-- content -->
          
           <ui:define name="content">
           <h:form>
           <div id="mainHeader"><h1>Project List</h1></div>
           <div id="mainContent">
           <div id="sectionHeader"><h2>About The Person</h2></div>
           <div id="projectLeftSide">
           <div id="entry">
           <label>Person Name:</label>
           <div class="input">
           <h:inputText id="personName" value="#{person.personName}" />
           </div>
           </div>
          
           <div id="entry">
           <label>Zip Code:</label>
           <div class="input">
           <h:selectOneMenu value="#{person.zipCodes}" id="zipCodes">
           <s:selectItems value="#{zipCodes.resultList}" var="zip" label="#{zip.zipcodeNumber}" />
           <s:convertEntity />
           </h:selectOneMenu>
           </div>
           </div>
           </div>
          
           <div id="buttonSection">
           <div class="button">
           <h:commandButton value="Add" action="#{thePerson.addNewPerson}"/>
           </div>
           <div class="button">
           <s:button id="cancelButton" value="Cancel" view="/main.xhtml" />
           </div>
           </div>
           </div>
           <div id="mainFooter"> </div>
           </h:form>
          
           </ui:define>
          </ui:composition>
          
          


          In bold red is what I want to do, just don't know how the backend should be coded...

          Here is my components.xml file:

          <?xml version="1.0" encoding="UTF-8"?>
          <components xmlns="http://jboss.com/products/seam/components"
           xmlns:core="http://jboss.com/products/seam/core"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation=
           "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd
          
           http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd">
          
           <core:init jndi-pattern="@jndiPattern@" debug="true"/>
          
           <core:manager conversation-timeout="120000"
           concurrent-request-timeout="500"
           conversation-id-parameter="cid"/>
          
          
          </components>
          


          Here is my persistence.xml file:

          <?xml version="1.0" encoding="UTF-8"?>
          <persistence xmlns="http://java.sun.com/xml/ns/persistence"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
           version="1.0">
          
           <persistence-unit name="myDatabase">
           <provider>org.hibernate.ejb.HibernatePersistence</provider>
           <jta-data-source>java:/OracleDS</jta-data-source>
           <properties>
           <property name="hibernate.hbm2ddl.auto" value="none"/>
           </properties>
           </persistence-unit>
          </persistence>
          


          Here is my main entity bean:

          package com.org.selectonemenu.entity;
          
          import javax.persistence.Column;
          import javax.persistence.Entity;
          import javax.persistence.FetchType;
          import javax.persistence.Id;
          import javax.persistence.JoinColumn;
          import javax.persistence.ManyToOne;
          import javax.persistence.Table;
          
          import org.jboss.seam.annotations.Name;
          
          @Entity
          @Name("person")
          @Table(name = "PERSON")
          public class Person implements java.io.Serializable {
          
           private long personId;
           private ZipCodes zipCodes;
           private String personName;
          
           public Person() {
           }
          
           public Person(long personId) {
           this.personId = personId;
           }
          
           public Person(long personId, ZipCodes zipCodes, String personName) {
           this.personId = personId;
           this.zipCodes = zipCodes;
           this.personName = personName;
           }
          
           @Id
           @Column(name = "PERSON_ID", unique = true, nullable = false, precision = 12, scale = 0)
           public long getPersonId() {
           return this.personId;
           }
          
           public void setPersonId(long personId) {
           this.personId = personId;
           }
          
           @ManyToOne(fetch = FetchType.LAZY)
           @JoinColumn(name = "ZIPCODE_ID")
           public ZipCodes getZipCodes() {
           return this.zipCodes;
           }
          
           public void setZipCodes(ZipCodes zipCodes) {
           this.zipCodes = zipCodes;
           }
          
           @Column(name = "PERSON_NAME", length = 100)
           public String getPersonName() {
           return this.personName;
           }
          
           public void setPersonName(String personName) {
           this.personName = personName;
           }
          
          }
          


          Here is the lookup Entity Bean:


          package com.org.selectonemenu.entity;
          
          import java.util.HashSet;
          import java.util.Set;
          import javax.persistence.CascadeType;
          import javax.persistence.Column;
          import javax.persistence.Entity;
          import javax.persistence.FetchType;
          import javax.persistence.Id;
          import javax.persistence.OneToMany;
          import javax.persistence.Table;
          
          import org.jboss.seam.annotations.Name;
          
          @Entity
          @Name("zipcodes")
          @Table(name = "ZIP_CODES")
          public class ZipCodes implements java.io.Serializable {
          
           private long zipcodeId;
           private String zipcodeNumber;
           private Set<Person> persons = new HashSet<Person>(0);
          
           public ZipCodes() {
           }
          
           public ZipCodes(long zipcodeId) {
           this.zipcodeId = zipcodeId;
           }
          
           public ZipCodes(long zipcodeId, String zipcodeNumber, Set<Person> persons) {
           this.zipcodeId = zipcodeId;
           this.zipcodeNumber = zipcodeNumber;
           this.persons = persons;
           }
          
           @Id
           @Column(name = "ZIPCODE_ID", unique = true, nullable = false, precision = 12, scale = 0)
           public long getZipcodeId() {
           return this.zipcodeId;
           }
          
           public void setZipcodeId(long zipcodeId) {
           this.zipcodeId = zipcodeId;
           }
          
           @Column(name = "ZIPCODE_NUMBER", length = 50)
           public String getZipcodeNumber() {
           return this.zipcodeNumber;
           }
          
           public void setZipcodeNumber(String zipcodeNumber) {
           this.zipcodeNumber = zipcodeNumber;
           }
          
           @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "zipCodes")
           public Set<Person> getPersons() {
           return this.persons;
           }
          
           public void setPersons(Set<Person> persons) {
           this.persons = persons;
           }
          
          }
          


          And finally here is my sfsb that I use to persist to the database:

          package com.org.selectonemenu.sfsb;
          
          import javax.ejb.Remove;
          import javax.ejb.Stateful;
          import javax.persistence.EntityManager;
          import javax.persistence.PersistenceContext;
          
          import org.jboss.seam.ScopeType;
          import org.jboss.seam.annotations.Destroy;
          import org.jboss.seam.annotations.In;
          import org.jboss.seam.annotations.Name;
          import org.jboss.seam.annotations.Out;
          import org.jboss.seam.annotations.Scope;
          
          import com.org.selectonemenu.entity.Person;
          import com.org.selectonemenu.interfaces.PersonMgr;
          
          @Stateful
          @Name("thePerson")
          @Scope(ScopeType.SESSION)
          public class PersonSFSB implements PersonMgr {
          
           @PersistenceContext
           private EntityManager entityManager;
          
           @In(required = false)
           @Out(required = false)
           private Person person;
          
          
           public void addNewPerson() {
           Person addPerson = person;
          
           addPerson.setZipCodes(person.getZipCodes());
           addPerson.setPersonName(person.getPersonName());
          
           entityManager.persist(addPerson);
          
           }
          
           @Destroy
           @Remove
           public void destroy() {
           }
          }
          


          So out of these files what do I need to change and what files do I need to add...As I mentioned before I am using the latest Seam Snapshot...I'm on JBoss Server 4.2.1

          Thank you for any help that anyone could provide to me.

          Blue



          • 2. Re: SelectOneMenu and OneToMany Seam 2.0 setup
            Blue Newbie

            Here is some more information...The stack trace error that I get when running my page:

            
            
            java.lang.IllegalArgumentException: Expected a child component type of UISelectItem/UISelectItems for component type javax.faces.SelectOne(zipCodes). Found null.
             at com.sun.faces.renderkit.RenderKitUtils.getSelectItems(RenderKitUtils.java:357)
             at com.sun.faces.renderkit.html_basic.MenuRenderer.getOptionNumber(MenuRenderer.java:675)
             at com.sun.faces.renderkit.html_basic.MenuRenderer.renderSelect(MenuRenderer.java:793)
             at com.sun.faces.renderkit.html_basic.MenuRenderer.encodeEnd(MenuRenderer.java:335)
             at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:836)
             at javax.faces.component.UIComponent.encodeAll(UIComponent.java:896)
             at javax.faces.render.Renderer.encodeChildren(Renderer.java:137)
             at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:812)
             at javax.faces.component.UIComponent.encodeAll(UIComponent.java:886)
             at javax.faces.component.UIComponent.encodeAll(UIComponent.java:892)
             at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:592)
             at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
             at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:216)
             at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:106)
             at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
             at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
             at javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
             at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
             at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
             at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:307)
             at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
             at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
             at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
             at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
             at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
             at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
             at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
             at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44)
             at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
             at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141)
             at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281)
             at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)
             at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
             at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
             at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
             at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:150)
             at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
             at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
             at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
             at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
             at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
             at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
             at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
             at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
             at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
             at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
             at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
             at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
             at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
             at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
             at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
             at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
             at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:580)
             at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
             at java.lang.Thread.run(Unknown Source)
            
            


            If anyone has any information on how to code the above issue, let me know.

            • 3. Re: SelectOneMenu and OneToMany Seam 2.0 setup
              Damian Harvey Master

              You really should take a look at some of the examples and read the reference. I found it *extremely* useful to use SeamGen to start with. Gives you something that works right away.

              For starters, you need something to provide a list of zipcodes. In your page you have:

              <s:selectItems value="#{zipCodes.resultList}" var="zip" label="#{zip.zipcodeNumber}" />


              But zipCodes is an entity and has no method called getResultList() or resultList(). You have 2 easy options:

              1. Add an entityQuery to your components.xml
              <framework:entity-query name="zipCodeList"
               ejbql="select z from ZipCodes z"/>

              2. Create a Bean that builds the list:
              @Name("zipCodeList")
              public class ZipCodeList() {
              @In(create=true)
              EntityManager entityManager; //actually you need to add this to your components.xml as well!
              
              public List<ZipCodes> getResultList() {
               return entityManager.createQuery("select z from ZipCodes z").getResultList();
              }
              }

              And then your page should have:
              <s:selectItems value="#{zipCodeList.resultList}" var="zip" label="#{zip.zipcodeNumber}" />


              Don't forget to add an entityManager to your components.xml:
              <persistence:managed-persistence-context name="entityManager"
               auto-create="true"
               persistence-unit-jndi-name="java:/OracleDS"/>


              Have a play with that. There are a few other things you need to fix up as well but you should find them.

              Cheers,

              Damian.

              • 4. Re: SelectOneMenu and OneToMany Seam 2.0 setup
                Blue Newbie

                Thanks Damian...I finally got it working...In hind sight it was such an easy solution.

                • 5. Re: SelectOneMenu and OneToMany Seam 2.0 setup
                  Blue Newbie

                  Oops...I guess I spoke too soon...I'm having a related issue...This time I'm having an issue with my edit mode...After the zipcode is added my app goes back to a the home screen where it displays the person in a table where you can edit it...When clicking on edit it brings up the correct record but the dropdown doesn't select the correct item.

                  Now I found out the I needed to override my main Entity and I did...Here is the code I used:

                  
                   @Override
                   public boolean equals(Object obj) {
                  
                   if(this == obj) {
                   return true;
                   }
                  
                   if ( !(obj instanceof Person) ) {
                   return false;
                   }
                  
                   final Person o = (Person) obj;
                  
                   return this.personId.equals( o.getPersonId() );
                   }
                  
                   @Override
                   public int hashCode() {
                   return personId.hashCode();
                   }
                  


                  After running the debugger I see the value that I need but is is in a Proxy wrapper...Does anyone know how to get to this information?

                  • 6. Re: SelectOneMenu and OneToMany Seam 2.0 setup
                    Pete Muir Master

                    What is in a proxy wrapper? The obj? That shouldn't matter, just cast it to Person.

                    • 7. Re: SelectOneMenu and OneToMany Seam 2.0 setup
                      Blue Newbie

                      Oh I'm sorry I forgot to post that I finally figured what the issue was...I changed from using @PersistenceContext to @In on the EntityManager variable in my stateful bean.