You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by "Holger Niehaus (JIRA)" <de...@myfaces.apache.org> on 2006/10/11 12:19:19 UTC

[jira] Created: (MYFACES-1452) selectBooleanCheckBox: Expected submitted value of type Boolean for Component

selectBooleanCheckBox: Expected submitted value of type Boolean for Component
-----------------------------------------------------------------------------

                 Key: MYFACES-1452
                 URL: http://issues.apache.org/jira/browse/MYFACES-1452
             Project: MyFaces Core
          Issue Type: Bug
          Components: JSR-127
    Affects Versions: 1.1.4, 1.1.1
         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.
-
If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

[jira] Commented: (MYFACES-1452) selectBooleanCheckBox: Expected submitted value of type Boolean for Component

Posted by "Paul Iov (JIRA)" <de...@myfaces.apache.org>.
    [ 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.