10 Replies Latest reply on Jul 4, 2006 3:47 PM by Jason Long

    @DataBinder and SelectItems Example

    Jason Long Master

      Is there any example of using these two together?

      I feel like I am jumping through hoops just to display a dropdown. Everything else in seam is a breeze.

      I know @DataBinder was added to give this kind of functionality, but a clear example would be greatly appreciated.

      This is the type of example I would love to see added to one of the existing Seam examples.

      These examples are the first place I look when wanting to try a new feature, but the examples are general and I would like to see more feature specific examples.

        • 1. Re: @DataBinder and SelectItems Example
          Jim Hazen Expert

          Yes. Let me head on over to the wiki and find a place to post it.

          -Jim

          • 2. Re: @DataBinder and SelectItems Example
            Jason Long Master

            Thanks Captain. I will be looking for it.

            You really seem to know your shiz.

            Do you have any suggestion for a solution to the following unrelated problem?

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

            • 3. Re: @DataBinder and SelectItems Example
              Jim Hazen Expert

              The @SelectItems example can be found on the Wiki here.

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

              It doesn't currently support selection, you'll need to use JSF EL to bind selected values to your controller. This should help you get your drop down started though.

              -Jim

              • 4. Re: @DataBinder and SelectItems Example
                Jason Long Master

                Thanks again Jim. I will look into it. Hopefully this type of functionality will be added to Seam sometime soon.

                Everyone needs dropdowns. :-} And using them should be a trivial matter.

                • 5. Re: @DataBinder and SelectItems Example
                  Jason Long Master

                  I teaked it a bit to make it a SFSB and pull a list of objects. For anyone else that tries this do not put valueMethod="???" if you change the value stragety to valueStrategy = SelectItems.Strategy.OBJECT.

                  I thought for sure I needed this, but errors occur after you add the converter. It kept returning the label value to the converter and chocking in my public String getAsString(FacesContext ctx, UIComponent component, Object value) method since I am looking it up by the id in the converter.

                  I haven't fully tested this out, but so far it really rocks. More people should post their stuff to the wiki like Jim did.

                  All I need now is a way to have my entites convert themselves so I do not have to go to the trouble of making one for every type.

                  Is anyone close to or have a solution for this?

                  @Name("selector")
                  @Stateful
                  @Scope(ScopeType.EVENT)
                  @Interceptors(SeamInterceptor.class)
                  public class SelectorAction implements Selector, Serializable
                  {
                   private static final long serialVersionUID = 1691282596699470676L;
                  
                   @Logger Log log;
                   @PersistenceContext EntityManager em;
                  
                   private Grade selected;
                   public Grade getSelected() { return selected; }
                   public void setSelected(Grade selected) { this.selected = selected; }
                  
                   @SelectItems(valueStrategy = SelectItems.Strategy.OBJECT, labelMethod = "getGrade)
                   public List items;
                  
                   @Factory("items")
                   public List getItems()
                   {
                   items = em.createQuery("from Grade").getResultList();
                   return items;
                   }
                  
                   public void select()
                   {
                   log.info("You selected: " + selected.getGrade());
                   }
                  
                   @Remove @Destroy
                   public void destroy() { }
                  }
                  


                  • 6. Re: @DataBinder and SelectItems Example
                    Jason Long Master

                    One more time. Than you Jim. I cleaned it up even more. I cannot believe how easy it is to use SelectItems now. Your code is really clear and easy to follow. I did have it working, but now it is cake.

                    :-) :+) :~)


                    @Name("selector")
                    @Stateless
                    @Interceptors(SeamInterceptor.class)
                    public class SelectorAction implements Selector
                    {
                     @EJB GradeDAO gradeDAO;
                    
                     @SelectItems(valueStrategy = SelectItems.Strategy.OBJECT, labelMethod = "getGrade")
                     private List gradeSelectItems;
                    
                     @Factory("gradeSelectItems")
                     public List getGradeSelectItems()
                     {
                     return gradeSelectItems = gradeDAO.getAllGrades();
                     }
                    }
                    


                    • 7. Re: @DataBinder and SelectItems Example
                      Jim Hazen Expert

                      I'm glad it's useful. If you put the following in your ejb-jar.xml you'll be able to remove the @Interceptors annotation from all of your components. That should clean up the code even more.

                      <ejb-jar>
                       <assembly-descriptor>
                       <interceptor-binding>
                       <ejb-name>*</ejb-name>
                       <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
                       </interceptor-binding>
                       </assembly-descriptor>
                      </ejb-jar>
                      


                      • 8. Re: @DataBinder and SelectItems Example
                        Jason Long Master

                        I was aware there was a way to remove that, but never looked into it.

                        I was able to clean up over 75 SLSB an SFSB. Thx for the tip.

                        What are your thoughts on a slick converter. I am using one that forces me to make my entites implement an interface.

                        Not a big problem, but I am looking for a slick way to avoid that.

                        • 9. Re: @DataBinder and SelectItems Example
                          Jim Hazen Expert

                          Do you really need a lot of converters? The @SelectItems binder does the conversion from whatever to SelectItem for you. I see you're using the Object strategy. The strategy works fine if you already have a lot of converters, but it wasn't my intention that you create additional converters to use @SelectItems.

                          Another way that would avoid the extra converter classes would be to write another binder that takes the selected value from the UISelect{One, Many} component and did the appropriate lookup from the original @SelectItems collection.

                          This has been on my TODO list for a while. Between holidays, weddings, and work my time just seems to evaporate. I will of course add this to my existing contribution once finished.

                          • 10. Re: @DataBinder and SelectItems Example
                            Jason Long Master

                            This is what I am using now. Every Entity in my project has an id named id that is a Long. So all I have to do is add the interface Idable to the entity. There is no doubt a better way. With discussions like this we can find an optimal technique that everyone can easily use with minimal setup.

                            Looking it up from the original list seems like a good idea.

                            Comments and or criticism are welcome.

                            public interface Idable {
                             public Long getId();
                            }
                            


                            I modifed some code from other posts and came up with the following. Generic converter.

                            public abstract class LookupConverter<T extends Idable> implements Converter
                            {
                             private Class<T> entityClass;
                             private EntityManager em;
                            
                             public LookupConverter(Class<T> entityClass, EntityManager em) {
                             this.entityClass = entityClass;
                             this.em = em;
                             }
                            
                             @SuppressWarnings("unchecked")
                             public String getAsString(FacesContext facesContext, UIComponent component, Object obj)
                             {
                             T t =(T) obj;
                             if(t == null || t.getId()==null)
                             {
                             return "";
                             }
                             else
                             {
                             return t.getId().toString();
                             }
                             }
                            
                             public Object getAsObject(FacesContext facesContext, UIComponent component, String str)
                             throws ConverterException
                             {
                             return getObject(str);
                             }
                            
                             private Object getObject(String str)
                             {
                             try
                             {
                             return em.find(entityClass, Long.valueOf(str));
                             }
                             catch (NumberFormatException e)
                             {
                             throw new ConverterException(new FacesMessage("You must select something."));
                             }
                             }
                            }
                            


                            I am using inner classes to deliver my converters form a SLSB. I am passing the EntityManager to the constructor.

                            @Stateless
                            @Name("converterFactory")
                            public class ConverterFactoryBean implements ConverterSizeFactory
                            {
                             @Logger private Log log;
                             @PersistenceContext EntityManager em;
                            
                             public Converter getSizeConverter()
                             {
                             return new SizeConverter(em);
                             }
                            
                             public static class SizeConverter extends LookupConverter<Size>
                             {
                             public SizeConverter(EntityManager em)
                             {
                             super(Size.class, em);
                             }
                             }
                            }
                            


                            I have a facelets taglib that creates the select field and renders the message in a mouseover icon with another custom facelets tag.
                            <ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
                             <tr class="tr0">
                             <td>#{selectFieldLabel}</td>
                             <td>
                             <h:selectOneMenu id="#{selectFieldId}"
                             value="#{selectFieldValue}"
                             class="select_std w200"
                             converter="#{selectFieldConverter}">
                             <f:selectItems value="#{selectFieldItems}" />
                             </h:selectOneMenu>
                             </td>
                             <td><pt:errorsField fieldId="#{selectFieldId}" /></td>
                             </tr>
                            </ui:composition>
                            


                            In the page I set it up as follows:
                             <pt:selectField2 selectFieldId="size"
                             selectFieldLabel="Size"
                             selectFieldValue="#{poCoupling.size}"
                             selectFieldItems="#{sizeSelectItems}"
                             selectFieldConverter="#{converterFactory.sizeConverter}"/>