[ 
https://issues.apache.org/jira/browse/MYFACES-1452?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12471087
 ] 

Paul Iov commented on MYFACES-1452:
-----------------------------------

Hi All.
I have the same issue with selectBooleanCheckbox SNAPSHOT-1.1.5 I'm not sure 
whether this behaviour violates the JSF specification directly. Any way, the 
description of value attribute from TLD says:
-----
The initial value of this component. This value is generally
set as a value-binding in the form #{myBean.myProperty}, where
myProperty can be any data-type of Java (also user-defined data-types),
if a converter for this data-type exists.
---

I've checked the source code and found, that the root of problem is the 
implementation of getBooleanValue() in 
org.apache.myfaces.shared.renderkit.RendererUtils class, which is called from 
encodeEnd() of renderer.
The custom converter as well as default one is cosequently ignored and 
IllegalArgumentException is thrown, if component value is neither of type 
Boolean nor null. (h:selectBooleanCheckbox and t:selectBooleanCheckbox are 
affected!)

It was difficult for me to check all dependencies of this function. I'm not 
sure, whether it is called by any other renderer with more 'strictly' 
behaviour. Keeping this in mind I decide to provide the new one, named 
getBooleanValueForCheckbox().  If I'm right and if my solution is correct, this 
function cann be renamed into getBooleanValue() and current one cann be 
replaced/overloaded with it, because my version hase 2 parameters. (Generally 
it's not a good idea to overload such methods.)

By the way: the same problem is solved in HtmlCalendar (which was a start point 
of my 'research' since my custom converter works with this component pretty 
well) directly in renderer, but I believe that it's not right to do this at 
'high' level, living unused methods at 'low' level.

Unfortunatelly I wasn't able to build wohl project due to time constraints. So 
I provide no path but post my source code right here and hope, that somebody 
cann review this and check in to the next nightly build.

SY,
paul
        


org.apache.myfaces.shared.renderkit.RendererUtils
<code>
    public static Boolean getBooleanValueForCheckbox(FacesContext facesContext, 
UIComponent component) {
        Object value = getObjectValue(component);
        
        //This call relays on the implementation of getObjectValue()!!!
        //If uiComponent is not an instance of ValueHolder, the
        //IllegalArgumentException should be already thrown.
        Converter converter = ((ValueHolder)uiComponent).getConverter();
        
        if (null == value || value instanceof Boolean){
                return (Boolean)value;
        }
        
        if (null == converter && value instanceof String) {
                //it's still correct to convert String into Boolean, because 
Boolean provides constructor Boolean(String x)!
                return new Boolean(value);
        }
        
        //If component provides no custom converter, we
        //must try to obtain a standard one from Application!
        if( null == converter ){
                try {
                converter = 
facesContext.getApplication().createConverter(value.getClass());
            }
            catch (FacesException ex) {
                throw new IllegalArgumentException("Component : " +
                        getPathToComponent(component)+
                        " expects value of type Boolean.\n"+
                        "Neither standard converter for " +
                        value.getClass().getName() +
                        " nor custom converter provided." );
            }
        }
        
        if (null != converter){
                try{
                    //Try to convert it into String. That is! The getAsObject() 
provides
                    //the convertion of string value's representation into 
custom user type. 
                    //We are expecting a Boolean, but the value itself is not a 
Boolean, so 
                    //we need to get String first.
                    String strValue = converter.getAsString(facesContext, 
component, value);
                    
                    boolean warn = (null == strValue);
                    warn = warn || (! 
strValue.equalsIgnoreCase(Boolean.TRUE.toString() &&
                                ! 
strValue.equalsIgnoreCase(Boolean.TRUE.toString()     );
                    
                    if ( wran ){
                        //Note that this situation is not an error! We have 
some converter
                        //and it got back some string, and no exception hase 
been thrown! 
                        log.warn("Component " + getPathToComponent(component) +
                                         " expects value of type Boolean. The 
value was converted with "+
                                         converter.getClass().getName()+
                                         " into " + strValue+ ", what is 
neither true nor false! false assumed.");
                    }
                    
                    return new Boolean(strValue);
                    
                }
                catch (ConverterException ex){
                        throw new IllegalArgumentException("Component : " +
                                                getPathToComponent(component)+
                                                " expects value of type 
Boolean.\n"+
                                                "Unable to convert " +
                                                value.getClass().getName() +
                                                " into Boolean.");
                }
                
                
                
        } else {
            throw new IllegalArgumentException("Component " +
                        getPathToComponent(component)+
                        " expects value of type Boolean but " +
                        value.getClass().getName() + " was found.");
        }
        
    }
</code>

/*    
change:
org.apache.myfaces.shared.renderkit.html.HtmlCheckboxRendererBase
*/
<code>
    public void encodeEnd(FacesContext facesContext, UIComponent uiComponent)
            throws IOException {
        
org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(facesContext,
 uiComponent, null);
        if (uiComponent instanceof UISelectBoolean) {
            
                Boolean value = 
org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanValue( uiComponent 
);
            
                boolean isChecked = value != null ? value.booleanValue() : 
false;
            renderCheckbox(facesContext, uiComponent, EXTERNAL_TRUE_VALUE,
                    null, false,isChecked, true);
        } else if (uiComponent instanceof UISelectMany) {
            renderCheckboxList(facesContext, (UISelectMany) uiComponent);
        } else {
            throw new IllegalArgumentException("Unsupported component class "
                    + uiComponent.getClass().getName());
        }
    }
    
    
    
/*    
into:
*/
    public void encodeEnd(FacesContext facesContext, UIComponent uiComponent)
                        throws IOException {
                
org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(
                                facesContext, uiComponent, null);
                if (uiComponent instanceof UISelectBoolean) {

                        // Boolean value =
                        // 
org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanValue(
                        // uiComponent );
                        Boolean value = 
org.apache.myfaces.shared.renderkit.RendererUtils
                                        
.getBooleanValueForCheckbox(facesContext, uiComponent);

                        // boolean isChecked = value != null ? 
value.booleanValue() : false;
                        boolean isChecked = value.booleanValue();

                        renderCheckbox(facesContext, uiComponent, 
EXTERNAL_TRUE_VALUE,
                                        null, false, isChecked, true);
                } else if (uiComponent instanceof UISelectMany) {
                        renderCheckboxList(facesContext, (UISelectMany) 
uiComponent);
                } else {
                        throw new IllegalArgumentException("Unsupported 
component class "
                                        + uiComponent.getClass().getName());
                }
        }
</code>

> selectBooleanCheckBox: Expected submitted value of type Boolean for Component
> -----------------------------------------------------------------------------
>
>                 Key: MYFACES-1452
>                 URL: https://issues.apache.org/jira/browse/MYFACES-1452
>             Project: MyFaces Core
>          Issue Type: Bug
>          Components: JSR-127
>    Affects Versions: 1.1.1, 1.1.4
>         Environment: Windows XP Professional SP 1; Tomcat 5.0.27
>            Reporter: Holger Niehaus
>
> I use following code in JSF:
> <h:selectBooleanCheckbox value="#{conf.zero}" 
> converter="NumberBooleanConverter" />
> conf.zero returns an Integer ( 0 or 1). Converter returns "true" or "false" 
> (String), but getAsString isn`t called. Instead the exception is thrown (see 
> below). Same effect with extension (x:selectBooleanCheckbox). For inputText 
> (<h:inputText value="#{conf.one}" converter="NumberBooleanConverter" />) it 
> works. Is it a similar reason as in Bug ADFFACES-38? Or am I on the wrong 
> track?
> Thrown exception:
> javax.faces.FacesException: Expected submitted value of type Boolean for 
> Component : {Component-Path : [Class: 
> javax.faces.component.UIViewRoot,ViewId: 
> /jsp/common/rechte/matrix_behoerde.jsp][Class: 
> javax.faces.component.html.HtmlForm,Id: behoerde_matrix][Class: 
> javax.faces.component.html.HtmlPanelGroup,Id: _id0][Class: 
> org.apache.myfaces.component.html.ext.HtmlDataTable,Id: matrix][Class: 
> javax.faces.component.UIColumn,Id: _id33][Class: 
> org.apache.myfaces.component.html.ext.HtmlSelectBooleanCheckbox,Id: _id35]}
>       
> org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:421)
>       
> org.apache.myfaces.application.jsp.JspViewHandlerImpl.renderView(JspViewHandlerImpl.java:234)
>       
> org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:352)
>       javax.faces.webapp.FacesServlet.service(FacesServlet.java:107)
>       
> org.apache.myfaces.component.html.util.ExtensionsFilter.doFilter(ExtensionsFilter.java:92)
>       
> org.apache.myfaces.component.html.util.ExtensionsFilter.doFilter(ExtensionsFilter.java:122)
>       de.filter.AccessFilter.doFilter(AccessFilter.java:93)

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