I do so love "secret sauce" answers.  I'm not surprised that it was something 
I did (or didn't do).  This is my first foray into JSF teritory after years of 
Spring MVC, Struts, and Webwork, and faces is by far the most frustrating 
framework of all.

Thanks for the quick reply!

___________________________________________________________
John O'Grady, Dragon Tamer
The important thing is not to stop questioning. - Albert Einstein
___________________________________________________________


-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of 
Jakob Korherr
Sent: Wednesday, January 06, 2010 3:09 PM
To: MyFaces Discussion
Subject: Re: Bad Bug: SelectOneMenu, SelectItems, _SystemItemsUtil, and the 
missing conversion

Hi John,

Use >itemValue="#{day}"< and it will work.

Regards,
Jakob Korherr


2010/1/6 Ogrady, John <[email protected]>

> Java 1.5
> MyFaces 1.1.7
> Tomahawk 1.1.9
> Spring 2.5.6
> Weblogic 9.2.3
>
>
> All I wanted to do was display a drop-down list of enums.  It seemed
> simple enough, with examples all over the 'net.  Apparently, myfaces
> has decided that using anything other than strings for a drop down is "no - 
> not yours".
>
> The setup:
>
>
> My example enum:
> ------------------------------------------------------------
> package com.facets;
> import java.util.Arrays;
> import java.util.List;
> public enum DaysOfWeek {
>    SUNDAY("Sunday"),
>    MONDAY("Monday"),
>    TUESDAY("Tuesday"),
>    WEDNESDAY("Wednesday"),
>    THURSDAY("Thursday"),
>    FRIDAY("Friday"),
>    SATURDAY("Saturday");
>
>    private static List<DaysOfWeek> dayList =
> Arrays.asList(DaysOfWeek.values());
>
>    private String label;
>
>    private DaysOfWeek(String label) {
>        this.label = label;
>    }
>    public String getLabel() {
>        return this.label;
>    }
>    public static DaysOfWeek getByLabel(String label) {
>        for(DaysOfWeek day : dayList) {
>            if(day.getLabel().equals(label)) {
>                return day;
>            }
>        }
>        return null;
>    }
>    public static final List<DaysOfWeek> getAllList() {
>        return dayList;
>    }
> }
> ------------------------------------------------------------
>
> JSF Converter:
> ------------------------------------------------------------
> package com.facets;
> import javax.faces.component.UIComponent;
> import javax.faces.context.FacesContext; import
> javax.faces.convert.Converter; import
> javax.faces.convert.ConverterException;
> public class DayEnumConverter implements Converter {
>    public Object getAsObject(FacesContext context, UIComponent
> component, String value)
>          throws ConverterException {
>        DaysOfWeek day = DaysOfWeek.getByLabel(value);
>        return (day==null ? DaysOfWeek.SUNDAY : day);
>    }
>    public String getAsString(FacesContext context, UIComponent
> component, Object object)
>          throws ConverterException {
>        if(object instanceof String) {
>            return (String)object;
>        }
>        if(!(object instanceof DaysOfWeek)) {
>            return "";
>        }
>        return ((DaysOfWeek)object).getLabel();
>    }
> }
> ------------------------------------------------------------
>
>
> Spring definition to get a list of the enums:
> ------------------------------------------------------------
> <bean id="daysEnumList"
>      class="com.facets.DaysOfWeek"
>      factory-method="getAllList" />
> ------------------------------------------------------------
>
>
> A simple drop down list made from an ArrayList of Enums.
> ------------------------------------------------------------
> <h:outputLabel for="daysOfWeekList" value="#{labels.dayList}" />
> <t:selectOneMenu id="daysOfWeekList"
>                 value="#{calendar.day}">
>    <t:selectItems var="day"
>                   value="#{daysEnumList}"
>                   itemLabel="#{day.label}"
>                   itemValue="#{day.label}"/>
>    <f:converter converterId="dayEnumConverter"/> </t:selectOneMenu>
> ------------------------------------------------------------
>
> Assumptions:
> 1) I'm using SpringBeanVariableResolver to get the "daysEnumList"
> object from the spring application context.
> 2) The problem goes away if I take the daysOfWeekList selectOneMenu
> control off the jsp page.  Also, there is another dropdown list using
> only strings and that works just fine.
> 3) The converter is properly listed in the faces-context.xml file, as
> it is called normally during the JSF lifecycle - at least until the bug hits.
>
>
> The Bug:
> When I submit a form containing the above selectOneMenu control, the
> list of which is created from a Java 5 Enum, I get this error in the logs:
>
> ------------------------------------------------------------
> DEBUG | 2010-01-06 13:28:53,912 | LifecycleImpl.java:178 | exiting
> from lifecycle.execute in RESTORE_VIEW(1) because getRenderResponse is
> true from one of the after listeners
> ------------------------------------------------------------
>
> This means that backing bean never gets bound to the form values, and
> the form action is never called.  I never get past the "Apply Request Values"
> step of the faces lifecycle.
>
> Take a look at this stack trace...
>
> ------------------------------------------------------------
> Daemon Thread [[ACTIVE] ExecuteThread: '0' for queue:
> 'weblogic.kernel.Default (self-tuning)'] (Suspended)
> _SelectItemsUtil.matchValue(Object, Iterator) line: 65
> HtmlSelectOneMenu(UISelectOne).validateValue(FacesContext, Object) line:
> 77
>  HtmlSelectOneMenu(UIInput).validate(FacesContext) line: 428
>  HtmlSelectOneMenu(UIInput).processValidators(FacesContext) line: 245
>  HtmlTag(UIComponentBase).processValidators(FacesContext) line: 866
>  HtmlForm(UIForm).processValidators(FacesContext) line: 78
>  UIViewRoot(UIComponentBase).processValidators(FacesContext) line: 866
>  UIViewRoot.processValidators(FacesContext) line: 169
>  ProcessValidationsExecutor.execute(FacesContext) line: 32
> LifecycleImpl.executePhase(FacesContext, PhaseExecutor,
> PhaseListenerManager) line: 105
>  LifecycleImpl.execute(FacesContext) line: 80
> FacesServlet.service(ServletRequest, ServletResponse) line: 143
>  StubSecurityHelper$ServletServiceAction.run() line: 225
> StubSecurityHelper.invokeServlet(ServletRequest, HttpServletRequest,
> ServletRequestImpl, ServletResponse, HttpServletResponse, Servlet)
> line: 127  ServletStubImpl.execute(ServletRequest, ServletResponse,
> FilterChainImpl)
> line: 283
>  TailFilter.doFilter(ServletRequest, ServletResponse, FilterChain)
> line: 26  FilterChainImpl.doFilter(ServletRequest, ServletResponse)
> line: 42  ExtensionsFilter.doFilter(ServletRequest, ServletResponse,
> FilterChain)
> line: 246
>  FilterChainImpl.doFilter(ServletRequest, ServletResponse) line: 42
> NavigationFilter.doFilter(ServletRequest, ServletResponse,
> FilterChain)
> line: 93
>  DelegatingFilterProxy.invokeDelegate(Filter, ServletRequest,
> ServletResponse, FilterChain) line: 236
> DelegatingFilterProxy.doFilter(ServletRequest, ServletResponse,
> FilterChain) line: 167
>  FilterChainImpl.doFilter(ServletRequest, ServletResponse) line: 42
> ExtensionsFilter.doFilter(ServletRequest, ServletResponse,
> FilterChain)
> line: 301
>  FilterChainImpl.doFilter(ServletRequest, ServletResponse) line: 42
>  WebAppServletContext$ServletInvocationAction.run() line: 3212
> AuthenticatedSubject.doAs(AbstractSubject, PrivilegedAction) line: 321
> SecurityManager.runAs(AuthenticatedSubject, AuthenticatedSubject,
> PrivilegedAction) line: 121
>  WebAppServletContext.securedExecute(HttpServletRequest,
> HttpServletResponse, boolean) line: 1983
> WebAppServletContext.execute(ServletRequestImpl, ServletResponseImpl)
> line: 1890
>  ServletRequestImpl.run() line: 1344
>  ExecuteThread.execute(Runnable) line: 209
>  ExecuteThread.run() line: 181
> ------------------------------------------------------------
>
> The bug is at line 65 of _SelectItemsUtil.
>
> ------------------------------------------------------------
> 44 public static boolean matchValue(Object value,
> 45                 Iterator selectItemsIter)
> 46 {
> 47     while (selectItemsIter.hasNext())
> 48     {
> 49         SelectItem item = (SelectItem) selectItemsIter.next();
> 50         if (item instanceof SelectItemGroup)
> 51         {
> 52             SelectItemGroup itemgroup = (SelectItemGroup) item;
> 53            SelectItem[] selectItems = itemgroup.getSelectItems();
> 54             if (selectItems != null
> 55                             && selectItems.length > 0
> 56                             && matchValue(value, Arrays.asList(
> 57                                             selectItems).iterator()))
> 58             {
> 59                 return true;
> 60             }
> 61         }
> 62         else
> 63         {
> 64             Object itemValue = item.getValue();
> 65             if (value==itemValue || (itemValue.equals(value)))
> 66             {
> 67                 return true;
> 68             }
> 69         }
> 70     }
> 71     return false;
> 72 }
> ------------------------------------------------------------
>
>
> The problem is that at this point, the "value" is the value that was
> selected in the dropdown.  The CONVERTED value - compliments of line
> 428 in the UIInput class:
>
> ------------------------------------------------------------
> 424 Object convertedValue = getConvertedValue(context,
> submittedValue);
> 425
> 426 if (!isValid()) return;
> 427
> 428 validateValue(context, convertedValue);
> ------------------------------------------------------------
>
> BUT - the "item" object is from an Iterator created on line 77 of
> UISelectOne, which only has the string values of the select component.
>
> This means when "item.getValue()" is called on line 64 (above), you
> are getting the string value from whatever selectitem entry is
> currently targeted - and of course the object version of the selected
> value isn't going to equal its non-converted string value.
>
> Either I'm missing something and there's some configuration I missed
> to fix this (which would make this behaviour a horrible default), or
> this is a pretty big bug that just cost me five hours of development time.
>
> If no one cares about JSF 1.1 implementations anymore, just let me
> know and I'll not spend the time posting here.  Otherwise, any chance
> this could be fixed?
>
> ___________________________________________________________
> John O'Grady
> Dragon Tamer
>
> Human beings, who are almost unique in having the ability to learn
> from the experience of others, are also remarkable for their apparent
> disinclination to do so.
> - Douglas Adams
>
> Those who do not learn from history are doomed to repeat it.
> - George Santayana
>
> Qui tacet consentit
> (Silence implies consent)
> ___________________________________________________________
>
>

Reply via email to