Tapestry
  1. Tapestry
  2. TAPESTRY-2157

ClassCastException in ExpressionBinding.setObject

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Critical Critical
    • Resolution: Unresolved
    • Affects Version/s: 4.1.5
    • Fix Version/s: None
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      Win XP, Tomcat 5.5

      Description

      I've been using this page structure for quite some time and it seems after upgrading to 4.1.5 from 4.1.1 something has regressed. It appears my BorderTab component is caching the page or page class when it shouldn't? essentially, i have a border component which wraps the bodyContent in a generic Form component. Inside this form (yet still inside the Border) i have some BorderTab components, each with a LinkSubmit component. Clicking these links navigates through the tabs, submitting their forms (empty in the example).

      Please run the attached example war file, it includes everything.

      1. click tab 1, tab 2, tab 3 etc - eventually the ClassCastException will be shown.

      note: clicking tab 1 recursively without clicking the other tabs does not cause the exception

      Exception message:
      Unable to update OGNL expression '<parsed OGNL expression>' of $ApplicationComponent_8@202687d[Page2/$Border.$BorderTab_1] to Page3: $Page2_15 cannot be cast to $Page1_14

      stack trace:
      $ASTChain_118168cf864.set($ASTChain_118168cf864.java)
      org.apache.tapestry.services.impl.ExpressionEvaluatorImpl.write(ExpressionEvaluatorImpl.java:179)
      $ExpressionEvaluator_118168cf818.write($ExpressionEvaluator_118168cf818.java)
      org.apache.tapestry.binding.ExpressionBinding.setObject(ExpressionBinding.java:224)
      $LinkSubmit_9.setSelected($LinkSubmit_9.java)
      org.apache.tapestry.form.AbstractSubmit.handleClick(AbstractSubmit.java:69)
      org.apache.tapestry.form.AbstractSubmit.rewindFormComponent(AbstractSubmit.java:63)
      org.apache.tapestry.form.AbstractFormComponent.renderComponent(AbstractFormComponent.java:90)
      org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:724)
      org.apache.tapestry.services.impl.DefaultResponseBuilder.render(DefaultResponseBuilder.java:187)
      org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:538)
      org.apache.tapestry.components.ElseBean.renderComponent(ElseBean.java:47)
      org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:724)
      org.apache.tapestry.services.impl.DefaultResponseBuilder.render(DefaultResponseBuilder.java:187)
      org.apache.tapestry.BaseComponent.renderComponent(BaseComponent.java:107)
      org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:724)
      org.apache.tapestry.services.impl.DefaultResponseBuilder.render(DefaultResponseBuilder.java:187)
      org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:538)
      org.apache.tapestry.components.IfBean.renderComponent(IfBean.java:94)
      org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:724)
      org.apache.tapestry.services.impl.DefaultResponseBuilder.render(DefaultResponseBuilder.java:187)
      org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:538)
      org.apache.tapestry.form.FormSupportImpl.rewind(FormSupportImpl.java:624)
      org.apache.tapestry.form.Form.renderComponent(Form.java:196)
      org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:724)
      org.apache.tapestry.services.impl.DefaultResponseBuilder.render(DefaultResponseBuilder.java:187)
      org.apache.tapestry.form.Form.rewind(Form.java:269)
      org.apache.tapestry.engine.RequestCycle.rewindForm(RequestCycle.java:469)
      org.apache.tapestry.form.Form.trigger(Form.java:280)
      org.apache.tapestry.engine.DirectService.triggerComponent(DirectService.java:166)
      org.apache.tapestry.engine.DirectService.service(DirectService.java:142)
      $IEngineService_118168cf76b.service($IEngineService_118168cf76b.java)
      org.apache.tapestry.services.impl.EngineServiceOuterProxy.service(EngineServiceOuterProxy.java:72)
      org.apache.tapestry.engine.AbstractEngine.service(AbstractEngine.java:241)
      org.apache.tapestry.services.impl.InvokeEngineTerminator.service(InvokeEngineTerminator.java:54)
      $WebRequestServicer_118168cf742.service($WebRequestServicer_118168cf742.java)
      $WebRequestServicer_118168cf73e.service($WebRequestServicer_118168cf73e.java)
      org.apache.tapestry.services.impl.WebRequestServicerPipelineBridge.service(WebRequestServicerPipelineBridge.java:61)
      $ServletRequestServicer_118168cf724.service($ServletRequestServicer_118168cf724.java)
      org.apache.tapestry.request.DecodedRequestInjector.service(DecodedRequestInjector.java:55)
      $ServletRequestServicerFilter_118168cf720.service($ServletRequestServicerFilter_118168cf720.java)
      $ServletRequestServicer_118168cf726.service($ServletRequestServicer_118168cf726.java)
      org.apache.tapestry.multipart.MultipartDecoderFilter.service(MultipartDecoderFilter.java:52)
      $ServletRequestServicerFilter_118168cf71e.service($ServletRequestServicerFilter_118168cf71e.java)
      $ServletRequestServicer_118168cf726.service($ServletRequestServicer_118168cf726.java)
      org.apache.tapestry.services.impl.SetupRequestEncoding.service(SetupRequestEncoding.java:53)
      $ServletRequestServicerFilter_118168cf722.service($ServletRequestServicerFilter_118168cf722.java)
      $ServletRequestServicer_118168cf726.service($ServletRequestServicer_118168cf726.java)
      $ServletRequestServicer_118168cf718.service($ServletRequestServicer_118168cf718.java)
      org.apache.tapestry.ApplicationServlet.doService(ApplicationServlet.java:126)
      org.apache.tapestry.ApplicationServlet.doPost(ApplicationServlet.java:171)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:710)

      1. Problem.war
        6.50 MB
        Paul Stanton

        Activity

        Hide
        Daniel Caldeweyher added a comment -

        If i understand correctly OGNL has undergone significant changes and no longer just evaluates the expression on demand but generates byte code and enhanced the pageclass during the first loading of the page. If my understanding is correct, then the problem might be its intregration into tapestry with ognl possibly generate byte code for a reference to the actual page object instead of the getPage() method of the component. This would explain the error message "$Page2_15 cannot be cast to $Page1_14"
        Daniel

        Show
        Daniel Caldeweyher added a comment - If i understand correctly OGNL has undergone significant changes and no longer just evaluates the expression on demand but generates byte code and enhanced the pageclass during the first loading of the page. If my understanding is correct, then the problem might be its intregration into tapestry with ognl possibly generate byte code for a reference to the actual page object instead of the getPage() method of the component. This would explain the error message "$Page2_15 cannot be cast to $Page1_14" Daniel
        Hide
        Paul Stanton added a comment - - edited

        daniel, thanks! this solved it:

        "ognl:pageName==page.pageName" -> "ognl:samePage"
        "ognl:page.nextPage" -> "ognl:nextPage"

        with relevant accessors.

        so then the bug is with tapestry or ognl? i think maybe tapestry:
        the page.nextPage call is what is causing the problem, when tapestry tries to resolve the expression in subsequent hits, it is caching the type of the object described by 'page'. this then throws a ClassCastException because the current 'page' is not of the same type as the cached 'page'.

        anyway, it works and obviously no one else is bumping up against it! so i'm happy.

        p.

        Show
        Paul Stanton added a comment - - edited daniel, thanks! this solved it: "ognl:pageName==page.pageName" -> "ognl:samePage" "ognl:page.nextPage" -> "ognl:nextPage" with relevant accessors. so then the bug is with tapestry or ognl? i think maybe tapestry: the page.nextPage call is what is causing the problem, when tapestry tries to resolve the expression in subsequent hits, it is caching the type of the object described by 'page'. this then throws a ClassCastException because the current 'page' is not of the same type as the cached 'page'. anyway, it works and obviously no one else is bumping up against it! so i'm happy. p.
        Hide
        Daniel Caldeweyher added a comment - - edited

        i have however come across other scenarions which might be related. OGNL gets confused sometimes and doesn't necessarily call the same method the the original ByteCode enhanced code generated. I would for example try replacing

        "ognl:pageName==page.pageName" with "ognl:samePage"

        and "ognl:page.nextPage" with "ognl:nextPage"

        given
        class BorderTab {
        public boolean isSamePage()

        { return getPageName().equals(getPage().getPageName()); }

        public String getNextPage()

        { return ((INextPage)getPage()).getNextPage(); }

        }

        I came across this ognl issue when our base application page contained the following methods:

        public Object coalesce(Collection objects)

        {..}
        public Object coalesce(Object[] objects) {..}

        During page loading and bytecode enhancement the one method was being called. but when it came to page rendering, "ognl:

        {landUseCode,'NA'}

        " was suddenly calling the other one, with an object[] as the first element in the collection. I had to remove the overloading and call the correct one internally, based on instanceof checks

        Show
        Daniel Caldeweyher added a comment - - edited i have however come across other scenarions which might be related. OGNL gets confused sometimes and doesn't necessarily call the same method the the original ByteCode enhanced code generated. I would for example try replacing "ognl:pageName==page.pageName" with "ognl:samePage" and "ognl:page.nextPage" with "ognl:nextPage" given class BorderTab { public boolean isSamePage() { return getPageName().equals(getPage().getPageName()); } public String getNextPage() { return ((INextPage)getPage()).getNextPage(); } } I came across this ognl issue when our base application page contained the following methods: public Object coalesce(Collection objects) {..} public Object coalesce(Object[] objects) {..} During page loading and bytecode enhancement the one method was being called. but when it came to page rendering, "ognl: {landUseCode,'NA'} " was suddenly calling the other one, with an object[] as the first element in the collection. I had to remove the overloading and call the correct one internally, based on instanceof checks
        Hide
        Daniel Caldeweyher added a comment -

        i didn't resolve it, i changed you SubmitLink to a DirectLink as we didn't need the submit behaviour.

        However seeing that it worked in 4.1.1 i would assume it is an OGNL issue. Didn't OGNL get upgraded between 4.1.1 and 4.1.2.? It might get confused by the parameter name "pageName", since this is also a tapestry shared property (http://tapestry.apache.org/tapestry4.1/usersguide/properties.html). Try changing the parameter to a different name.

        Show
        Daniel Caldeweyher added a comment - i didn't resolve it, i changed you SubmitLink to a DirectLink as we didn't need the submit behaviour. However seeing that it worked in 4.1.1 i would assume it is an OGNL issue. Didn't OGNL get upgraded between 4.1.1 and 4.1.2.? It might get confused by the parameter name "pageName", since this is also a tapestry shared property ( http://tapestry.apache.org/tapestry4.1/usersguide/properties.html ). Try changing the parameter to a different name.
        Hide
        Paul Stanton added a comment -

        how did you resolve that daniel?

        further testing proves this is an issue since 4.1.2, but works 100% in 4.1.1

        Show
        Paul Stanton added a comment - how did you resolve that daniel? further testing proves this is an issue since 4.1.2, but works 100% in 4.1.1
        Hide
        Daniel Caldeweyher added a comment -

        Hi Paul,

        i don't believe this is a tapestry 4.1.5 issue. I was getting the same exception when I was first starting to use your BorderTab component in our app, then using 4.1.2.

        Daniel

        Show
        Daniel Caldeweyher added a comment - Hi Paul, i don't believe this is a tapestry 4.1.5 issue. I was getting the same exception when I was first starting to use your BorderTab component in our app, then using 4.1.2. Daniel
        Hide
        Paul Stanton added a comment - - edited

        if you need any more info let me know. i have the example ready to run on my system.

        p.

        Show
        Paul Stanton added a comment - - edited if you need any more info let me know. i have the example ready to run on my system. p.

          People

          • Assignee:
            Jesse Kuhnert
            Reporter:
            Paul Stanton
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:

              Development