You're welcome!
Here's the explanation to your problem:
You always have to set itemValue to an object with the same type as the
value attribute of the surrounding t:selectXXX. This is also the type you
have to write a converter for.
In your case:
<t:selectOneMenu id="daysOfWeekList"
value="#{calendar.day}">
<t:selectItems var="day"
value="#{daysEnumList}"
itemLabel="#{day.label}"
itemValue="#{day}"/>
<f:converter converterId="dayEnumConverter"/>
</t:selectOneMenu>
#{calendar.day} references to a property of type DaysOfWeek, thus itemValue
has also to be of type DaysOfWeek and you have to write a converter, because
it is no String.
If you set itemValue="#{day.label}", you'll also have to change
#{calendar.day} to point to a String property. But that's of course not what
you want!
I hope it is now clear to you.
And sorry for my first short answer, I did not have the time to write this
earlier.
Regards,
Jakob Korherr
2010/1/6 Ogrady, John <[email protected]>
> 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)
> > ___________________________________________________________
> >
> >
>