myfaces-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jakob Korherr <jakob.korh...@gmail.com>
Subject Re: Bad Bug: SelectOneMenu, SelectItems, _SystemItemsUtil, and the missing conversion
Date Wed, 06 Jan 2010 20:08:52 GMT
Hi John,

Use »itemValue="#{day}"« and it will work.

Regards,
Jakob Korherr


2010/1/6 Ogrady, John <john.ogrady@citi.com>

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

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message