10 Replies Latest reply on Feb 11, 2007 1:12 PM by pmuir

    How to use si:selectItems with an object that has a String i

    lawrieg

      Hi,

      I'm a Seam newbie and I'm trying to get my head around si:selectItems and the Seam application framework.

      My CustomerType object has a String id so when I initially tried to use si:selectItems without creating and specifying a converter I got an exception:

      <h:selectOneMenu value="#{ customerHome.instance.customerType}" id="customerType">
       <si:selectItems value="#{customerTypes.resultList}" var="customerType" label="#{customerType.name}" noSelectionLabel="Please Select..." />
      </h:selectOneMenu>

      javax.faces.convert.ConverterException: javax.faces.application.FacesMessage@154fe9c com.mycomp.myapp.CustomerType
       at org.jboss.seam.selectitems.ui.BasicEntityConverter.getIdAsString(BasicEntityConverter.java:61)
       at org.jboss.seam.selectitems.jsf.EntityConverter.convertToString(EntityConverter.java:36)
       at org.jboss.seam.selectitems.jsf.SelectItemsConverter.getAsString(SelectItemsConverter.java:131)
       at org.apache.myfaces.shared_impl.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:544)
      ...
      
      Caused by: java.lang.NullPointerException
       at org.jboss.seam.selectitems.ui.BasicEntityConverter.getIdAsString(BasicEntityConverter.java:59)
       ... 43 more


      So I then created a CustomerTypeSelectItemsConverter which extends SelectItemsConverter:

      @Name("customerTypeSelectItemsConverter")
      public class CustomerTypeSelectItemsConverter extends org.jboss.seam.selectitems.jsf.SelectItemsConverter {
      
       @Override
       protected Object convertToObject(FacesContext arg0, UIComponent arg1, String arg2)
       throws ConverterException {
       return arg2;
       }
      
       @Override
       protected String convertToString(FacesContext arg0, UIComponent arg1, Object arg2)
       throws ConverterException {
       return ((CustomerType)arg2).getId();
       }
      
      }

      and changed my facelets code:

      <h:selectOneMenu value="#{customerHome.instance.customerType}" converter="#{customerTypeSelectItemsConverter}" id="customerType">
       <si:selectItems value="#{customerTypes.resultList}" var="customerType" label="#{customerType.name}" noSelectionLabel="Please Select..." />
      </h:selectOneMenu>
      


      This gets my drop down list displaying correctly but gives me a validation error "value is not valid" when I try to save. I presume this means that I should be returning a CustomerType object (rather than the CustomerType object's id) from CustomerTypeSelectItemsConverter's convertToObject() method?

      Am I on the right lines now?

      If so, what is the correct way for me to obtain the CustomerType object? Should I somehow be getting the List from the Seam Application Framework EntityQuery object ("customerTypes") that was used to populate the si:selectItems tag and then iterating the List to find find the CustomerType with the specified id? Or is there a better way?

      Any help would be greatly appreciated as I can't find any examples which match my problem and I'm struggling to find any answers...

      Thanks,

      Lawrie

        • 1. Re: How to use si:selectItems with an object that has a Stri
          pmuir

          Post the CustomerType class (include type annotations)

          • 2. Re: How to use si:selectItems with an object that has a Stri
            lawrieg

            CustomerType class:

            @Entity
            @Table(name = "CUSTOMER_TYPE", catalog = "CustomerBuilder")
            public class CustomerType implements java.io.Serializable {
            
             private String id;
             private String name;
             private Set<Script> scripts = new HashSet<Script>(0);
            
             public CustomerType() {
             }
            
             public CustomerType(String id, String name) {
             this.id = id;
             this.name = name;
             }
             public CustomerType(String id, String name, Set<Script> scripts) {
             this.id = id;
             this.name = name;
             this.scripts = scripts;
             }
            
             @Id @GeneratedValue
             @Column(name = "ID", unique = true, nullable = false, length = 1)
             @NotNull
             @Length(max = 1)
             public String getId() {
             return this.id;
             }
            
             public void setId(String id) {
             this.id = id;
             }
            
             @Column(name = "NAME", nullable = false, length = 50)
             @NotNull
             @Length(max = 50)
             public String getName() {
             return this.name;
             }
            
             public void setName(String name) {
             this.name = name;
             }
             @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
             @JoinTable(name = "CUSTOMER_TYPE_SCRIPT",
             joinColumns={@JoinColumn(name = "CUSTOMER_TYPE_ID")},
             inverseJoinColumns={@JoinColumn(name = "SCRIPT_ID")})
             public Set<Script> getScripts() {
             return this.scripts;
             }
            
             public void setScripts(Set<Script> scripts) {
             this.scripts = scripts;
             }
            
            }
            


            • 3. Re: How to use si:selectItems with an object that has a Stri
              pmuir

              You're on the right track with your first approach - you can use the inbuilt EntityConverter (which is used automatically) as a converter. It looks to me like you are trying to use objects in the list with it that have null ids (which is why you get an NPE). Is this intentional?

              • 4. Re: How to use si:selectItems with an object that has a Stri
                lawrieg


                Thanks for your help Pete.

                From what I read in the wiki, I thought I should be able to use the inbuilt EntityConverter, so I was a bit surprised when this didn't work...

                I've just checked, and the two objects in the list both have non-null ids - do you have any other ideas what might be causing the problem?

                Cheers,

                Lawrie.

                • 5. Re: How to use si:selectItems with an object that has a Stri
                  pmuir

                  I notice your @Id annotation is on the method rather than on the field - now that should work, and no one has said it doesn't - but I don't use it so can't confirm. I'll do some tests to see if that is the problem later.

                  • 6. Re: How to use si:selectItems with an object that has a Stri
                    lawrieg

                    I stepped through the code and you are quite right that the first CampaignType object passed to BasicEntityConverter's getIdAsString method has null values in its fields.

                    If I modify the BasicEntityConverter code to not throw an exception, then I see that on the second and third calls to the getIdAsString method, the entity argument contains the CampaignType objects I would expect.

                    customerTypes.resultList is populated by a Seam Application Framework Entity-Query:

                    <framework:entity-query name="customerTypes" ejbql="select customerType from CustomerType customerType" />
                    


                    I've checked that my entity-query only returns two CustomerType objects which have non-null id values.

                    My si:selectItems tag is as follows:

                    <h:selectOneMenu value="#{customerHome.instance.customerType}" id="customerType">
                     <si:selectItems value="#{customerTypes.resultList}" var="customerType" label="#{customerType.name}" noSelectionLabel="Please Select..." />
                    </h:selectOneMenu>


                    So now I'm more than a bit confused as to how a CustomerType with a null id value is being passed to BasicEntityConverter's getIdAsString method.

                    Does the object from the <h:selectOneMenu> value property get passed to the BasicEntityConverter??? The reason I ask is because I'm creating a new Customer and therefore #{customerHome.instance.customerType} would initially contain a new instance of CustomerType. If so, how do you work around this?

                    Any help would be very much appreciated as I'm starting to tear my hair out...

                    Cheers,

                    Lawrie

                    • 7. Re: How to use si:selectItems with an object that has a Stri
                      lawrieg

                      I've done some more investigating and the problem is that the <h:selectOneMenu> value property (which is #{customerHome.instance.customerType}) is passed to the BasicEntityConverter, and that customerHome.instance.customerType holds a new instance of CustomerType which doesn't have any fields set.

                      The issue seems to stem from the seam-gen generated entity home code:

                      @Name("customerHome")
                      public class CustomerHome extends EntityHome<Customer> {
                      
                       @In(value = "#{customerTypeHome.instance}", required = false)
                       CustomerType customerType;
                       @In(value = "#{refCustomerStatusHome.instance}", required = false)
                       RefCustomerStatus refCustomerStatus;
                      
                       public void setCustomerId(Integer id) {
                       setId(id);
                       }
                      
                       public Integer getCustomerId() {
                       return (Integer) getId();
                       }
                      
                       @Override
                       protected Customer createInstance() {
                       Customer result = new Customer();
                       result.setCustomerType(customerType);
                       result.setRefCustomerStatus(refCustomerStatus);
                       return result;
                       }
                      
                       public List<Activity> getActivities() {
                       return getInstance() == null ? null : new ArrayList<Activity>(
                       getInstance().getActivities());
                       }
                      
                      }
                      


                      Do I need to change the seam-gen generated code (i.e. is it incorrect)? (I presume I do if the BasicEntityConverter doesn't convert a null id to whatever is required for the "no item selected" item in the drop down list to be selected.

                      What value for #{customerHome.instance.customerType} in (<h:selectOneMenu> value property) would cause my drop down to correctly have the "Please Select..." (no item selected) item selected when the page is displayed? Should my CustomerHome createInstance() method instead be setting the customerType to null rather than #{customerTypeHome.instance}???

                      Any help would be really appreciated as I'm struggling to get my code working with <h:selectOneMenu> & <si:selectItems> and none of the examples are really helping to clarify things...

                      Thanks in advance,

                      Lawrie.

                      • 8. Re: How to use si:selectItems with an object that has a Stri
                        pmuir

                        Thanks for chasing down the problem here. I need to work on the EntityConverter to fix this. I'll do that later today.

                        • 9. Re: How to use si:selectItems with an object that has a Stri
                          damianharvey

                          I'm facing the same problem with a Seam-gen application.

                          It works fine if I don't use the EntityHome - ie:

                          <h:selectOneMenu value="#{customer.customerType}" id="customerType">

                          rather than
                          <h:selectOneMenu value="#{customerHome.instance.customerType}" id="customerType">


                          Unfortunately this means changing all of the code that was generated. Any chance that a fix has been done for this?

                          Thanks,

                          Damian.

                          • 10. Re: How to use si:selectItems with an object that has a Stri
                            pmuir

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

                            Please test this (with s:selectItems rather than si:selectItems) - sorry about the time delay in getting this out :(