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