MyFaces Core
  1. MyFaces Core
  2. MYFACES-1891

ClassCastException in converter when Hiding / Showing unselected selectOneRadio

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.2.3
    • Fix Version/s: 1.1.7, 1.2.7
    • Component/s: None
    • Labels:
      None
    • Environment:
      MyFaces 1.2.3, Spring WebFlow 2.0.2, RichFaces 3.2.1, Tomahawk 1.1.6, Facelets 1.1.15.B1, Tomcat 6.0.16

      Description

      See the attached example.

      When the block with the selectOneRadio ist shown, then hidden and then shown again a ClassCastException occurs in the Converter. The selectOneRadio has as submittedValue org.apache.myfaces.shared_impl.renderkit.RendererUtils$1, for which the conversion is done.

      javax.faces.FacesException: Exception while calling encodeEnd on component :

      {Component-Path : [Class: org.ajax4jsf.component.AjaxViewRoot,ViewId: /WEB-INF/pages/schnellerfassung/dea/dea.xhtml][Class: javax.faces.component.html.HtmlForm,Id: form][Class: org.apache.myfaces.custom.div.Div,Id: hideableBlock][Class: javax.faces.component.html.HtmlSelectOneRadio,Id: selectOneRadio]}

      at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:610)
      at org.ajax4jsf.renderkit.RendererBase.renderChild(RendererBase.java:286)
      at org.ajax4jsf.renderkit.RendererBase.renderChildren(RendererBase.java:262)
      at org.ajax4jsf.renderkit.RendererBase.renderChild(RendererBase.java:284)
      at org.ajax4jsf.renderkit.RendererBase.renderChildren(RendererBase.java:262)
      at org.ajax4jsf.renderkit.RendererBase.renderChild(RendererBase.java:284)
      at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:125)
      at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxChildren(AjaxChildrenRenderer.java:68)
      at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:116)
      at org.ajax4jsf.renderkit.AjaxContainerRenderer.encodeAjax(AjaxContainerRenderer.java:123)
      at org.ajax4jsf.component.AjaxViewRoot.encodeAjax(AjaxViewRoot.java:673)
      at org.ajax4jsf.component.AjaxViewRoot.encodeChildren(AjaxViewRoot.java:544)
      at javax.faces.component.UIComponent.encodeAll(UIComponent.java:239)
      at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:592)
      at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
      at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:189)
      at org.springframework.faces.webflow.JsfView.render(JsfView.java:92)
      at org.springframework.webflow.engine.ViewState.render(ViewState.java:240)
      at org.springframework.webflow.engine.ViewState.resume(ViewState.java:199)
      at org.springframework.webflow.engine.Flow.resume(Flow.java:535)
      at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:261)
      at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:153)
      at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:173)
      at org.springframework.webflow.mvc.servlet.FlowController.handleRequest(FlowController.java:172)
      at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
      at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at com.metzler.ec.web.filter.RendererFilter.doFilter(RendererFilter.java:183)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:154)
      at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:260)
      at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:366)
      at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:493)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:359)
      at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
      at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:268)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:268)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:87)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:61)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:229)
      at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
      at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:174)
      at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
      at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
      at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
      at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
      at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
      at java.lang.Thread.run(Thread.java:595)
      Caused by: javax.faces.convert.ConverterException: java.lang.ClassCastException: org.apache.myfaces.shared_impl.renderkit.RendererUtils$1
      at javax.faces.convert.IntegerConverter.getAsString(IntegerConverter.java:85)
      at org.apache.myfaces.shared_impl.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:628)
      at org.apache.myfaces.shared_impl.renderkit.html.HtmlRadioRendererBase.encodeEnd(HtmlRadioRendererBase.java:91)
      at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:607)
      ... 87 more
      Caused by: java.lang.ClassCastException: org.apache.myfaces.shared_impl.renderkit.RendererUtils$1
      at javax.faces.convert.IntegerConverter.getAsString(IntegerConverter.java:81)
      ... 90 more

      1. example.zip
        0.8 kB
        Patrick Schmidt
      2. RendererUtils.patch
        1 kB
        Paul Rivera
      3. RendererUtils_1.2.6_patched.java
        40 kB
        Patrick Schmidt
      4. MYFACES-1891-custom-converter.patch
        0.7 kB
        Leonardo Uribe

        Issue Links

          Activity

          Hide
          Christian Kaltepoth added a comment -

          I have experienced similar problems dealing with the selectOneRadio component.

          The root of these issues seems to be RendererUtils.NOTHING which is not handled
          correctly in all cases. The stacktrace shows, that this special constant is
          passed to the IntegerConverter for conversion.

          See MYFACES-1567 for a similar issue with RendererUtils.NOTHING.

          Show
          Christian Kaltepoth added a comment - I have experienced similar problems dealing with the selectOneRadio component. The root of these issues seems to be RendererUtils.NOTHING which is not handled correctly in all cases. The stacktrace shows, that this special constant is passed to the IntegerConverter for conversion. See MYFACES-1567 for a similar issue with RendererUtils.NOTHING.
          Hide
          Paul Rivera added a comment -

          patch to org.apache.myfaces.shared.renderkit.RendererUtils

          Show
          Paul Rivera added a comment - patch to org.apache.myfaces.shared.renderkit.RendererUtils
          Hide
          Paul Rivera added a comment -

          I was able to replicate this bug. I've attached a patch that fixes this. Christian is right, it is rooted in the handling of RendererUtils.NOTHING.
          The patch I've provided adds the code below to the beginning of the getConvertedStringValue() method of RendererUtils.

          + if (RendererUtils.NOTHING.equals(value))

          { + return ""; + }

          +
          if (converter == null) {
          if (value == null) {
          return "";

          The idea of this fix is partly from the patch Christopher Pierce provided for MYFACES-1567. Although, here, the check for NOTHING should be outside the block where converter is checked for null.

          The second fix provided in my patch is:
          public static final String SELECT_ITEM_LIST_ATTR = RendererUtils.class.getName() + ".LIST";
          public static final String EMPTY_STRING = "";

          • public static final Object NOTHING = new Serializable() {};
            + public static final Object NOTHING = new Serializable() {
            + public boolean equals(Object o)
            + {
            + if(o != null)
            +
            Unknown macro: {+ if(o.getClass().equals(this.getClass())) + { + return true; + }+ }

            + return false;
            + }
            + };

          The NOTHING object has to have a modified equals() method to return true as long as the object is of the same class. Without this modification,
          RendererUtils.NOTHING.equals(value) is never satisfied since 'value' is a field of a Component that gets serialized/deserialized along with the UIViewRoot in JspStateManagerImpl. If it gets serialized and deserialized, regardless of server or client state saving method, 'value' will be a new instance and RendererUtils.NOTHING.equals(value) will return false.

          You can also observe this when using SelectOneListbox. Tracing through the code, you can see that in HtmlRendererUtils.getSubmittedOrSelectedValuesAsSet() Line 365:

          else if(org.apache.myfaces.shared_impl.renderkit.RendererUtils.NOTHING.equals(lookup))

          { lookupSet = Collections.EMPTY_SET; }

          else

          { lookupSet = Collections.singleton(lookup); }

          the 'else if' condition will never be satisfied even if nothing is selected in the selectOneListbox. This is because lookup is of another instance that came from serialization/deserialization of the RendererUtils.NOTHING object. Therefore, lookupSet will never be the EMPTY_SET. Instead, it will be a collection containing the single element RendererUtils.NOTHING. Although this makes the code only marginally slower, I think it's still best to fix it.

          I've also tested SelectOneListbox and SelectManyCheckbox if they experienced problems when nothing is selected. But I've encountered no bugs when testing them.

          Show
          Paul Rivera added a comment - I was able to replicate this bug. I've attached a patch that fixes this. Christian is right, it is rooted in the handling of RendererUtils.NOTHING. The patch I've provided adds the code below to the beginning of the getConvertedStringValue() method of RendererUtils. + if (RendererUtils.NOTHING.equals(value)) { + return ""; + } + if (converter == null) { if (value == null) { return ""; The idea of this fix is partly from the patch Christopher Pierce provided for MYFACES-1567 . Although, here, the check for NOTHING should be outside the block where converter is checked for null. The second fix provided in my patch is: public static final String SELECT_ITEM_LIST_ATTR = RendererUtils.class.getName() + ".LIST"; public static final String EMPTY_STRING = ""; public static final Object NOTHING = new Serializable() {}; + public static final Object NOTHING = new Serializable() { + public boolean equals(Object o) + { + if(o != null) + Unknown macro: {+ if(o.getClass().equals(this.getClass())) + { + return true; + }+ } + return false; + } + }; The NOTHING object has to have a modified equals() method to return true as long as the object is of the same class. Without this modification, RendererUtils.NOTHING.equals(value) is never satisfied since 'value' is a field of a Component that gets serialized/deserialized along with the UIViewRoot in JspStateManagerImpl. If it gets serialized and deserialized, regardless of server or client state saving method, 'value' will be a new instance and RendererUtils.NOTHING.equals(value) will return false. You can also observe this when using SelectOneListbox. Tracing through the code, you can see that in HtmlRendererUtils.getSubmittedOrSelectedValuesAsSet() Line 365: else if(org.apache.myfaces.shared_impl.renderkit.RendererUtils.NOTHING.equals(lookup)) { lookupSet = Collections.EMPTY_SET; } else { lookupSet = Collections.singleton(lookup); } the 'else if' condition will never be satisfied even if nothing is selected in the selectOneListbox. This is because lookup is of another instance that came from serialization/deserialization of the RendererUtils.NOTHING object. Therefore, lookupSet will never be the EMPTY_SET. Instead, it will be a collection containing the single element RendererUtils.NOTHING. Although this makes the code only marginally slower, I think it's still best to fix it. I've also tested SelectOneListbox and SelectManyCheckbox if they experienced problems when nothing is selected. But I've encountered no bugs when testing them.
          Hide
          Patrick Schmidt added a comment -

          Paul, I tried your patch and it worked perfectly.

          Thanks a lot.

          Is there a possibility that it makes it into the next official release?

          Show
          Patrick Schmidt added a comment - Paul, I tried your patch and it worked perfectly. Thanks a lot. Is there a possibility that it makes it into the next official release?
          Hide
          Paul Rivera added a comment -

          Hi Patrick!

          This patch will have to be reviewed by a MyFaces committer. As of now, I cannot give you a definite date on when this patch will get released. Please stay tuned.

          Show
          Paul Rivera added a comment - Hi Patrick! This patch will have to be reviewed by a MyFaces committer. As of now, I cannot give you a definite date on when this patch will get released. Please stay tuned.
          Hide
          Leonardo Uribe added a comment -

          Suppose this scenario

          <h:form id="form">
          <h:commandButton value="#

          {hideShowBean.hidden? 'Show' : 'Hide'}

          "
          action="#

          {hideShowBean.toggleHideShow}

          " immediate="true" />
          <t:div id="hideableBlock" rendered="#

          {!hideShowBean.hidden}

          ">
          <div><h:selectOneRadio id="selectOneRadio"
          value="#

          {hideShowBean.property}

          ">
          <f:selectItem itemLabel="Option Z" itemValue="" />
          <f:selectItem itemLabel="Option A" itemValue="1" />
          <f:selectItem itemLabel="Option B" itemValue="2" />
          <f:selectItem itemLabel="Option C" itemValue="3" />
          </h:selectOneRadio></div>
          <div><h:inputText id="inputText" required="true" /></div>
          </t:div>
          <h:messages />
          </h:form>

          According to the spec (see MYFACES-1759), itemValue="" is equivalent to null, so when you hide and show several times, the result should be the same (Option Z selected).

          To be according to the spec, on myfaces core 1.2 RendererUtils.NOTHING should be removed and used null instead. But on myfaces core 1.1 this spec does not enforce us, so to remain compatibility this solution is acceptable. But we need a patch against 1.1

          Show
          Leonardo Uribe added a comment - Suppose this scenario <h:form id="form"> <h:commandButton value="# {hideShowBean.hidden? 'Show' : 'Hide'} " action="# {hideShowBean.toggleHideShow} " immediate="true" /> <t:div id="hideableBlock" rendered="# {!hideShowBean.hidden} "> <div><h:selectOneRadio id="selectOneRadio" value="# {hideShowBean.property} "> <f:selectItem itemLabel="Option Z" itemValue="" /> <f:selectItem itemLabel="Option A" itemValue="1" /> <f:selectItem itemLabel="Option B" itemValue="2" /> <f:selectItem itemLabel="Option C" itemValue="3" /> </h:selectOneRadio></div> <div><h:inputText id="inputText" required="true" /></div> </t:div> <h:messages /> </h:form> According to the spec (see MYFACES-1759 ), itemValue="" is equivalent to null, so when you hide and show several times, the result should be the same (Option Z selected). To be according to the spec, on myfaces core 1.2 RendererUtils.NOTHING should be removed and used null instead. But on myfaces core 1.1 this spec does not enforce us, so to remain compatibility this solution is acceptable. But we need a patch against 1.1
          Hide
          Paul Rivera added a comment -

          Hi Leonardo,

          I tested your scenario with the myfaces jars prior to my patch (Myfaces 1.2.2). This was the behavior:

          Option Z was selected by default.
          Pressing hide/show does not throw exception and will still select Option Z.
          If I select option A, B, or C and then press hide/show, it will still be the same button selected once the page loads.

          I also testd it with the patched jars (MyFaces 1.2.4-SNAPSHOT). Same behavior as above.

          I also tested for the case where your SelectItem gets created in your bean like:
          new SelectItem(null, "Null SelectItem", "This is a null select item.")
          The outcome is the same as your scenario. The item with the null value gets selected by default. When this selectItem gets rendered, the value attribute of its input tag is equal to "".

          I think there's nothing wrong with your scenario. Unless this is not the desired behavior.

          As for JSF 1.2 Spec item #69:
          69 - Permit the passing of a null value to SelectItem.setValue().

          RenderUtils.NOTHING only gets assigned to the value attribute of your UISelectOne or UISelectMany(in in the example given, it is assigned to HtmlRadioRenderer). I believe it does not get assigned to the value of SelectItem.

          I think that the only way to have the value of your SelectItem to null is by creating it this way:
          new SelectItem(null, "Null SelectItem", "This is a null select item.")
          Because if you use the tag similar to this:
          <f:selectItem itemLabel="Option Z" itemValue="" />
          it will set the value of your SelectItem to "".

          In either case, during the update values phase, bean.property will be set to 0 and not null. Is the JSF 1.2 spec trying to say that whenever a SelectItem of value equal to null gets selected, the backing bean property should be null instead of 0?

          Also, the patch I provided here before was for RendererUtils which belongs to myfaces-shared-core. myfaces-shared-core is shared between myfaces 1.1 and 1.2 right? Or is there a way to modify RendererUtils without affecting myfaces 1.2 if we are to patch myfaces 1.1 only?

          Show
          Paul Rivera added a comment - Hi Leonardo, I tested your scenario with the myfaces jars prior to my patch (Myfaces 1.2.2). This was the behavior: Option Z was selected by default. Pressing hide/show does not throw exception and will still select Option Z. If I select option A, B, or C and then press hide/show, it will still be the same button selected once the page loads. I also testd it with the patched jars (MyFaces 1.2.4-SNAPSHOT). Same behavior as above. I also tested for the case where your SelectItem gets created in your bean like: new SelectItem(null, "Null SelectItem", "This is a null select item.") The outcome is the same as your scenario. The item with the null value gets selected by default. When this selectItem gets rendered, the value attribute of its input tag is equal to "". I think there's nothing wrong with your scenario. Unless this is not the desired behavior. As for JSF 1.2 Spec item #69: 69 - Permit the passing of a null value to SelectItem.setValue(). RenderUtils.NOTHING only gets assigned to the value attribute of your UISelectOne or UISelectMany(in in the example given, it is assigned to HtmlRadioRenderer). I believe it does not get assigned to the value of SelectItem. I think that the only way to have the value of your SelectItem to null is by creating it this way: new SelectItem(null, "Null SelectItem", "This is a null select item.") Because if you use the tag similar to this: <f:selectItem itemLabel="Option Z" itemValue="" /> it will set the value of your SelectItem to "". In either case, during the update values phase, bean.property will be set to 0 and not null. Is the JSF 1.2 spec trying to say that whenever a SelectItem of value equal to null gets selected, the backing bean property should be null instead of 0? Also, the patch I provided here before was for RendererUtils which belongs to myfaces-shared-core. myfaces-shared-core is shared between myfaces 1.1 and 1.2 right? Or is there a way to modify RendererUtils without affecting myfaces 1.2 if we are to patch myfaces 1.1 only?
          Hide
          Leonardo Uribe added a comment -

          myfaces-shared-core 2.0.x is for 1.1 and 3.0.x for 1.2. There are different, so on this type of changes it is necessary to make changes on both branches.

          I noted that h:commandButton has immediate=false. The result of doing this is that the backing bean are not updated. Test it with immediate="false" on both 1.1 and 1.2 (without Z element).

          Show
          Leonardo Uribe added a comment - myfaces-shared-core 2.0.x is for 1.1 and 3.0.x for 1.2. There are different, so on this type of changes it is necessary to make changes on both branches. I noted that h:commandButton has immediate=false. The result of doing this is that the backing bean are not updated. Test it with immediate="false" on both 1.1 and 1.2 (without Z element).
          Hide
          Leonardo Uribe added a comment -

          I have commited a variant of the patch provided on 3.0.x branch (1.2) (the equals code provided it is not necessary and the check could be done after trying to check string), but if you test the same example with myfaces core 1.1 (the commandButton has immediate="false") causes a validation error.

          RendererUtils.NOTHING is set on decode method of h:selectOneXXX, but it does not set on backing bean (it is replaced as null), since is converted before set the value, so It's ok if we let this.

          The only thing left is the myfaces core 1.1 validation error.

          Show
          Leonardo Uribe added a comment - I have commited a variant of the patch provided on 3.0.x branch (1.2) (the equals code provided it is not necessary and the check could be done after trying to check string), but if you test the same example with myfaces core 1.1 (the commandButton has immediate="false") causes a validation error. RendererUtils.NOTHING is set on decode method of h:selectOneXXX, but it does not set on backing bean (it is replaced as null), since is converted before set the value, so It's ok if we let this. The only thing left is the myfaces core 1.1 validation error.
          Hide
          Leonardo Uribe added a comment -

          I have tried the change on 1.1 and changed the bean to hold as property not an Integer rather a String, and it works well (dissapear the problem of have to click twice the button).

          I'll commit on 1.1 branch and close this issue.

          Show
          Leonardo Uribe added a comment - I have tried the change on 1.1 and changed the bean to hold as property not an Integer rather a String, and it works well (dissapear the problem of have to click twice the button). I'll commit on 1.1 branch and close this issue.
          Hide
          Leonardo Uribe added a comment -

          Thanks to Paul Rivera for provide us this patch

          Show
          Leonardo Uribe added a comment - Thanks to Paul Rivera for provide us this patch
          Hide
          Patrick Schmidt added a comment -

          Hello,

          the problem still exists in MyFaces Core 1.2.6.

          I have a selectOneMenu with a value binding to a boolean property.

          In the boolean converter the ClassCastException still occurs.

          ...
          Caused by: javax.faces.convert.ConverterException: java.lang.ClassCastException: org.apache.myfaces.shared_impl.renderkit.RendererUtils$1 cannot be cast to java.lang.Boolean
          at javax.faces.convert.BooleanConverter.getAsString(BooleanConverter.java:91)
          at org.apache.myfaces.shared_impl.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:630)
          at org.apache.myfaces.shared_impl.renderkit.html.HtmlRadioRendererBase.encodeEnd(HtmlRadioRendererBase.java:91)
          at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:624)
          ... 110 more
          Caused by: java.lang.ClassCastException: org.apache.myfaces.shared_impl.renderkit.RendererUtils$1 cannot be cast to java.lang.Boolean
          at javax.faces.convert.BooleanConverter.getAsString(BooleanConverter.java:87)
          ... 113 more

          In RendererUtils there are some tests that value equals NOTHING. However the equals method of the NOTHING-Serializable isn't overriden. Therefore it has no effect.

          Overriding the equals method as in the patch of paul works.

          Attached you find the modified RendererUtils of 1.2.6.

          Show
          Patrick Schmidt added a comment - Hello, the problem still exists in MyFaces Core 1.2.6. I have a selectOneMenu with a value binding to a boolean property. In the boolean converter the ClassCastException still occurs. ... Caused by: javax.faces.convert.ConverterException: java.lang.ClassCastException: org.apache.myfaces.shared_impl.renderkit.RendererUtils$1 cannot be cast to java.lang.Boolean at javax.faces.convert.BooleanConverter.getAsString(BooleanConverter.java:91) at org.apache.myfaces.shared_impl.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:630) at org.apache.myfaces.shared_impl.renderkit.html.HtmlRadioRendererBase.encodeEnd(HtmlRadioRendererBase.java:91) at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:624) ... 110 more Caused by: java.lang.ClassCastException: org.apache.myfaces.shared_impl.renderkit.RendererUtils$1 cannot be cast to java.lang.Boolean at javax.faces.convert.BooleanConverter.getAsString(BooleanConverter.java:87) ... 113 more In RendererUtils there are some tests that value equals NOTHING. However the equals method of the NOTHING-Serializable isn't overriden. Therefore it has no effect. Overriding the equals method as in the patch of paul works. Attached you find the modified RendererUtils of 1.2.6.
          Hide
          Leonardo Uribe added a comment -

          The problem described before is a variant of the original exception.

          The solution is a little bit different from the proposed on the modified RendererUtils file (but the file helps to find what's wrong, thanks Patrick for the patch). It is add this code to getConvertedStringValue (look the last return):

          public static String getConvertedStringValue(FacesContext context,
          UIComponent component, Converter converter, Object value) {
          if (converter == null) {
          if (value == null)

          { return ""; }
          else if (value instanceof String) { return (String) value; } else if (RendererUtils.NOTHING.equals(value)) { return ""; }

          else

          { throw new IllegalArgumentException( "Value is no String (class=" + value.getClass().getName() + ", value=" + value + ") and component " + component.getClientId(context) + "with path: " + getPathToComponent(component) + " does not have a Converter"); }

          }

          if (RendererUtils.NOTHING.equals(value))

          { return converter.getAsString(context, component, ""); }

          else

          { return converter.getAsString(context, component, value); }

          }

          If a converter is used and RendererUtils.NOTHING is set, we should call converter.getAsString with empty string as value (right now RendererUtils.NOTHING is passed, but it must not, because this var is used when no selection is set by the user and then pass it as null value).

          The fix should be done for both 1.1 and 1.2 branches

          Show
          Leonardo Uribe added a comment - The problem described before is a variant of the original exception. The solution is a little bit different from the proposed on the modified RendererUtils file (but the file helps to find what's wrong, thanks Patrick for the patch). It is add this code to getConvertedStringValue (look the last return): public static String getConvertedStringValue(FacesContext context, UIComponent component, Converter converter, Object value) { if (converter == null) { if (value == null) { return ""; } else if (value instanceof String) { return (String) value; } else if (RendererUtils.NOTHING.equals(value)) { return ""; } else { throw new IllegalArgumentException( "Value is no String (class=" + value.getClass().getName() + ", value=" + value + ") and component " + component.getClientId(context) + "with path: " + getPathToComponent(component) + " does not have a Converter"); } } if (RendererUtils.NOTHING.equals(value)) { return converter.getAsString(context, component, ""); } else { return converter.getAsString(context, component, value); } } If a converter is used and RendererUtils.NOTHING is set, we should call converter.getAsString with empty string as value (right now RendererUtils.NOTHING is passed, but it must not, because this var is used when no selection is set by the user and then pass it as null value). The fix should be done for both 1.1 and 1.2 branches

            People

            • Assignee:
              Leonardo Uribe
              Reporter:
              Patrick Schmidt
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development