[ 
https://issues.apache.org/jira/browse/MYFACES-1493?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12606998#action_12606998
 ] 

K. Ghadami commented on MYFACES-1493:
-------------------------------------

i analized and soleved the Problem.
The renderer trys to use the value in the select items to render the value of 
the option tags - which is wrong!
Because the value of the selectitem is not need to be a string. Some people 
mean u just need a converter but that is not what the jsf spec says.

So what we need is a renderer that simply use numbers for the value of the 
option tag. 
If like t share my render with u, that aceppt all all objets in the selectItem 
value.
it only testet for selectOneMenu. You can find the current code on my german 
blog:

http://art-of-software-engineering.blogspot.com/2008/06/selectonemenu-und-die.html

in the facesconfig i registered my renderer:

<render-kit>
<renderer>
<description>Renderer accepting objekts as value for select itmes</description>
<component-family>javax.faces.SelectOne</component-family>
<renderer-type>javax.faces.Menu</renderer-type>
<renderer-class>jsf.MenuRenderer</renderer-class>
</renderer>
</render-kit>


Here the comes the render. it would be nice if some on could provide a real 
patch(svn diff) so the pain will be gone in the next version of myfaces, ;-)
i changed, and mixed up so much code, that i am not quit sure how to provied a 
good patch: 

package jsf;

import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.component.UISelectMany;
import javax.faces.component.UISelectOne;
import javax.faces.component.html.HtmlSelectManyMenu;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.model.SelectItem;
import javax.faces.model.SelectItemGroup;

import org.apache.myfaces.shared_impl.component.EscapeCapable;
import org.apache.myfaces.shared_impl.renderkit.JSFAttr;
import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
import org.apache.myfaces.shared_impl.renderkit.html.HTML;
import org.apache.myfaces.shared_impl.renderkit.html.HtmlRenderer;
import org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils;

/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */

/* 14.06.2008 modified by K.Ghadami
 * Now accepting non Sting values in selectItems 
*/   

/**
 * X-CHECKED: tlddoc of h:selectManyListbox
 * 
 * @author Manfred Geiler (latest modification by $Author: matzew $)
 * @author Thomas Spiegl
 * @version $Revision: 597729 $ $Date: 2007-11-23 14:25:55 -0500 (Fri, 23 Nov
 *          2007) $
 */
public class MenuRenderer extends HtmlRenderer {
        // private static final Log log = 
LogFactory.getLog(HtmlMenuRenderer.class);

        public void encodeEnd(FacesContext facesContext, UIComponent component)
                        throws IOException {
                RendererUtils.checkParamValidity(facesContext, component, null);

                if (component instanceof UISelectMany) {
                        HtmlRendererUtils.renderMenu(facesContext,
                                        (UISelectMany) component, 
isDisabled(facesContext,
                                                        component));
                } else if (component instanceof UISelectOne) {

                        renderMenu(facesContext, (UISelectOne) component, 
isDisabled(
                                        facesContext, component));
                } else {
                        throw new IllegalArgumentException("Unsupported 
component class "
                                        + component.getClass().getName());
                }
        }

        public void renderMenu(FacesContext facesContext, UISelectOne 
uiComponent,
                        boolean disabled) throws IOException {

                ResponseWriter writer = facesContext.getResponseWriter();

                writer.startElement(HTML.SELECT_ELEM, uiComponent);
                HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, 
facesContext);
                writer.writeAttribute(HTML.NAME_ATTR, uiComponent
                                .getClientId(facesContext), null);

                List<SelectItem> selectItemList;
                Converter converter;
                selectItemList = RendererUtils
                                .getSelectItemList((UISelectOne) uiComponent);
                converter = HtmlRendererUtils.findUIOutputConverterFailSafe(
                                facesContext, uiComponent);
                int size = 1;
                if (size == Integer.MIN_VALUE) {
                        // No size given (Listbox) --> size is number of select 
items
                        writer.writeAttribute(HTML.SIZE_ATTR, Integer
                                        .toString(selectItemList.size()), null);
                } else {
                        writer.writeAttribute(HTML.SIZE_ATTR, 
Integer.toString(size), null);
                }
                HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
                                
HTML.SELECT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED);
                if (disabled) {
                        writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, 
null);
                }

                if (HtmlRendererUtils.isReadOnly(uiComponent)) {
                        writer.writeAttribute(HTML.READONLY_ATTR, 
HTML.READONLY_ATTR, null);
                }

                UISelectOne uiSelectOne = (UISelectOne) uiComponent;

                /*The value was looked up during the validate phase. 
                 * Even if the hole list of selectitmes know cheched by a 
backing bean
                 * we have the origial selected object to compare. thats better 
than
                 * to check against the index, which would lead to
                 * strange results
                 * */
                Object lookupValue = uiSelectOne.getValue();

                renderSelectOptions(facesContext, uiComponent, converter,
                                lookupValue, selectItemList, 0);
                // bug #970747: force separate end tag
                writer.writeText("", null);
                writer.endElement(HTML.SELECT_ELEM);

        }

        public void renderSelectOptions(FacesContext context,
                        UIComponent component, Converter converter,
                        Object lookupObject, List<SelectItem> selectItemList, 
Integer index)
                        throws IOException {
                ResponseWriter writer = context.getResponseWriter();

                for (Iterator<SelectItem> it = selectItemList.iterator(); 
it.hasNext();) {
                        SelectItem selectItem = it.next();

                        if (selectItem instanceof SelectItemGroup) {
                                writer.startElement(HTML.OPTGROUP_ELEM, 
component);
                                writer.writeAttribute(HTML.LABEL_ATTR, 
selectItem.getLabel(),
                                                null);
                                SelectItem[] selectItems = ((SelectItemGroup) 
selectItem)
                                                .getSelectItems();
                                renderSelectOptions(context, component, 
converter,
                                                lookupObject, 
Arrays.asList(selectItems), index);
                                writer.endElement(HTML.OPTGROUP_ELEM);
                        } else {
                                index++;

                                writer.write('\t');
                                writer.startElement(HTML.OPTION_ELEM, 
component);

                                writer.writeAttribute(HTML.VALUE_ATTR, 
index.toString(), null);

                                if (selectItem.getValue().equals(lookupObject)) 
{
                                        
writer.writeAttribute(HTML.SELECTED_ATTR,
                                                        HTML.SELECTED_ATTR, 
null);
                                }

                        }

                        boolean disabled = selectItem.isDisabled();
                        if (disabled) {
                                writer.writeAttribute(HTML.DISABLED_ATTR, 
HTML.DISABLED_ATTR,
                                                null);
                        }

                        String labelClass = null;
                        boolean componentDisabled = 
isTrue(component.getAttributes().get(
                                        "disabled"));

                        if (componentDisabled || disabled) {
                                labelClass = (String) 
component.getAttributes().get(
                                                JSFAttr.DISABLED_CLASS_ATTR);
                        } else {
                                labelClass = (String) 
component.getAttributes().get(
                                                JSFAttr.ENABLED_CLASS_ATTR);
                        }
                        if (labelClass != null) {
                                writer.writeAttribute("class", labelClass, 
"labelClass");
                        }

                        boolean escape;
                        if (component instanceof EscapeCapable) {
                                escape = ((EscapeCapable) component).isEscape();
                        } else {
                                escape = 
RendererUtils.getBooleanAttribute(component,
                                                JSFAttr.ESCAPE_ATTR, true); // 
default is to escape
                        }

                        if (escape || selectItem.isEscape()) {
                                writer.writeText(selectItem.getLabel(), null);
                        } else {
                                writer.write(selectItem.getLabel());
                        }

                        writer.endElement(HTML.OPTION_ELEM);
                }
        }

        private static boolean isTrue(Object obj) {
                if (!(obj instanceof Boolean))
                        return false;

                return ((Boolean) obj).booleanValue();
        }

        protected boolean isDisabled(FacesContext facesContext,
                        UIComponent uiComponent) {
                // TODO: overwrite in extended HtmlMenuRenderer and check for
                // enabledOnUserRole
                if (uiComponent instanceof HtmlSelectManyMenu) {
                        return ((HtmlSelectManyMenu) uiComponent).isDisabled();
                } else if (uiComponent instanceof HtmlSelectOneMenu) {
                        return ((HtmlSelectOneMenu) uiComponent).isDisabled();
                } else {
                        return 
org.apache.myfaces.shared_impl.renderkit.RendererUtils
                                        .getBooleanAttribute(
                                                        uiComponent,
                                                        
org.apache.myfaces.shared_impl.renderkit.html.HTML.DISABLED_ATTR,
                                                        false);
                }
        }

        public void decode(FacesContext facesContext, UIComponent uiComponent) {
                org.apache.myfaces.shared_impl.renderkit.RendererUtils
                                .checkParamValidity(facesContext, uiComponent, 
null);

                if (uiComponent instanceof UISelectMany) {
                        HtmlRendererUtils.decodeUISelectMany(facesContext, 
uiComponent);
                } else if (uiComponent instanceof UISelectOne) {
                        HtmlRendererUtils.decodeUISelectOne(facesContext, 
uiComponent);
                } else {
                        throw new IllegalArgumentException("Unsupported 
component class "
                                        + uiComponent.getClass().getName());
                }
        }

        public Object getConvertedValue(FacesContext facesContext,
                        UIComponent uiComponent, Object submittedValue)
                        throws ConverterException {
                org.apache.myfaces.shared_impl.renderkit.RendererUtils
                                .checkParamValidity(facesContext, uiComponent, 
null);

                if (uiComponent instanceof UISelectMany) {
                        return 
org.apache.myfaces.shared_impl.renderkit.RendererUtils
                                        
.getConvertedUISelectManyValue(facesContext,
                                                        (UISelectMany) 
uiComponent, submittedValue);
                } else if (uiComponent instanceof UISelectOne) {
                        UISelectOne d = (UISelectOne) uiComponent;
                        
                        List<SelectItem> selectItemList = RendererUtils
                        .getSelectItemList(d);
                        
                        if (submittedValue instanceof String){
                        
                        
                        Object x = lookup(facesContext, 
selectItemList.toArray(new SelectItem[0]), Integer
                                        .valueOf((String) submittedValue), 0);
                        return x;
                        } else {
                                //Log.info(submittedValue);
                                //return submittedValue;
                                //nothing was selected in the menu, so we need 
to return null to pass the validation phase
                                return null;
                        }

                } else {
                        throw new IllegalArgumentException("Unsupported 
component class "
                                        + uiComponent.getClass().getName());
                }
        }

        private Object lookup(FacesContext facesContext, SelectItem[] 
selectItemList,
                        int submittedValue, Integer index) {

                        for (SelectItem selectItem :selectItemList) {
                

                        if (selectItem instanceof SelectItemGroup) {
                                SelectItem[] selectItems = ((SelectItemGroup) 
selectItem)
                                                .getSelectItems();
                                Object res = lookup(facesContext, selectItems, 
submittedValue,
                                                index);
                                if (res != null)
                                        return res;

                        } else {
                                index++;

                                if (index.equals(submittedValue)) {
                                        return selectItem.getValue();
                                }
                        }
                }
                return null;
        }

}


> h:selectOneMenu should resolve non-string objects in the value property 
> without a converter
> -------------------------------------------------------------------------------------------
>
>                 Key: MYFACES-1493
>                 URL: https://issues.apache.org/jira/browse/MYFACES-1493
>             Project: MyFaces Core
>          Issue Type: Improvement
>    Affects Versions: 1.1.4
>         Environment: JDK 1.5.0_08
>            Reporter: Paul Norrie
>            Priority: Minor
>
> h:selectOneMenu appears to require a converter if the object bound in the 
> value field is not a java.lang.String.
> To reproduce:
> JSP snippet:
>    <h:dataTable var="row" value="#{bean.rows}>
>       <h:column>
>          <h:selectOneMenu value="#{row.day}"/>
>       <h:column>
>    </h:dataTable>
> Java snippet (backing bean):
>   private List<UserClass> rows;
>    public List getRows(){
>       return rows;
>    }
> Java snippet (UserClass):
>    static enum Day {MON, TUE, WED, THU, FRI, SAT, SUN};
>    private Day day;
>    public getDay(){
>       return day;
>    }
> Expected:
> the enum Day to be converted to a string and display either "MON", "TUE", 
> etc...
> Actual:
> java.lang.IllegalArgumentException: Value is no String (class=UserClass$Day, 
> value=MON)
>    at 
> org.apache.myfaces.shared_impl.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:536)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.getSubmittedOrSelectedValuesAsSet(HtmlRendererUtils.java:321)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.internalRenderSelect(HtmlRendererUtils.java:296)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.renderMenu(HtmlRendererUtils.java:252)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlMenuRendererBase.encodeEnd(HtmlMenuRendererBase.java:54)
>         at 
> javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:536)
>         at 
> org.apache.myfaces.shared_impl.renderkit.RendererUtils.renderChild(RendererUtils.java:442)
>         at 
> org.apache.myfaces.shared_impl.renderkit.RendererUtils.renderChildren(RendererUtils.java:419)
>         at 
> org.apache.myfaces.shared_impl.renderkit.RendererUtils.renderChild(RendererUtils.java:440)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlTableRendererBase.renderColumnBody(HtmlTableRendererBase.java:332)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlTableRendererBase.encodeColumnChild(HtmlTableRendererBase.java:301)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlTableRendererBase.encodeInnerHtml(HtmlTableRendererBase.java:277)
>         at 
> org.apache.myfaces.shared_impl.renderkit.html.HtmlTableRendererBase.encodeChildren(HtmlTableRendererBase.java:123)
>         at 
> javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:524)
> The RI and ADF Faces will quite happily work, however myfaces doc's seem to 
> mean that a convertor is needed.  
> See also http://www.mail-archive.com/[EMAIL PROTECTED]/msg29588.html 
> This is a pain - could it be fixed please?

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to