Tapestry 5
  1. Tapestry 5
  2. TAP5-1656

Problem when inheriting annotated methods from a abstract superclass

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.3
    • Fix Version/s: 5.3
    • Component/s: tapestry-core
    • Labels:
      None

      Description

      I have a parent class and two subclasses.
      The parent is declared as a abstract class as the logic in the subclasses will differ slightly but they are all using Parent.tml.
      This has been tested with all classes in the package "com.example.newapp.base.Parent" and I also tried to move Parent.class to the "com.example.newapp.base" package.

      (I will keep a testapp on https://github.com/sigbjornt/T5.3-beta-6-bug-demo for a while)

      public abstract class Parent {
      @Log
      public void setupRender() {
      }
      }
      public class ChildA extends Parent

      { .... }

      public class ChildB extends Parent {
      @Override
      public void setupRender()

      { super.setupRender(); }

      ....
      }

      This will be ok as ChildB is accessed before ChildA.
      If ChildA is accessed before ChildB (or ChildB does not call "super.setupRender();"), we get an exeption.

      --stacktrace –

      [ERROR] pages.ChildA Render queue error in SetupRender[ChildA]: Unable to locate Method public void setupRender(): com.example.newapp.pages.ChildA.setupRender()
      org.apache.tapestry5.ioc.internal.util.TapestryException: Unable to locate Method public void setupRender(): com.example.newapp.pages.ChildA.setupRender()
      at org.apache.tapestry5.internal.structure.ComponentPageElementImpl$AbstractPhase.invoke(ComponentPageElementImpl.java:153)
      at org.apache.tapestry5.internal.structure.ComponentPageElementImpl$SetupRenderPhase.render(ComponentPageElementImpl.java:181)
      at org.apache.tapestry5.internal.services.RenderQueueImpl.run(RenderQueueImpl.java:72)
      at org.apache.tapestry5.internal.services.PageRenderQueueImpl.render(PageRenderQueueImpl.java:124)
      at $PageRenderQueue_19bce9b139ae.render(Unknown Source)
      at $PageRenderQueue_19bce9b139ad.render(Unknown Source)
      at org.apache.tapestry5.internal.services.MarkupRendererTerminator.renderMarkup(MarkupRendererTerminator.java:37)
      at org.apache.tapestry5.services.TapestryModule$31.renderMarkup(TapestryModule.java:1998)
      at $MarkupRenderer_19bce9b139b0.renderMarkup(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$30.renderMarkup(TapestryModule.java:1982)
      at $MarkupRenderer_19bce9b139b0.renderMarkup(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$29.renderMarkup(TapestryModule.java:1964)
      at $MarkupRenderer_19bce9b139b0.renderMarkup(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$28.renderMarkup(TapestryModule.java:1949)
      at $MarkupRenderer_19bce9b139b0.renderMarkup(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$27.renderMarkup(TapestryModule.java:1935)
      at $MarkupRenderer_19bce9b139b0.renderMarkup(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$26.renderMarkup(TapestryModule.java:1917)
      at $MarkupRenderer_19bce9b139b0.renderMarkup(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$25.renderMarkup(TapestryModule.java:1898)
      at $MarkupRenderer_19bce9b139b0.renderMarkup(Unknown Source)
      at $MarkupRenderer_19bce9b139ac.renderMarkup(Unknown Source)
      at org.apache.tapestry5.internal.services.PageMarkupRendererImpl.renderPageMarkup(PageMarkupRendererImpl.java:47)
      at $PageMarkupRenderer_19bce9b139a9.renderPageMarkup(Unknown Source)
      at org.apache.tapestry5.internal.services.PageResponseRendererImpl.renderPageResponse(PageResponseRendererImpl.java:67)
      at $PageResponseRenderer_19bce9b1395f.renderPageResponse(Unknown Source)
      at org.apache.tapestry5.internal.services.PageRenderRequestHandlerImpl.handle(PageRenderRequestHandlerImpl.java:64)
      at org.apache.tapestry5.services.TapestryModule$38.handle(TapestryModule.java:2227)
      at $PageRenderRequestHandler_19bce9b13961.handle(Unknown Source)
      at $PageRenderRequestHandler_19bce9b1395b.handle(Unknown Source)
      at org.apache.tapestry5.internal.services.ComponentRequestHandlerTerminator.handlePageRender(ComponentRequestHandlerTerminator.java:48)
      at org.apache.tapestry5.services.InitializeActivePageName.handlePageRender(InitializeActivePageName.java:47)
      at $ComponentRequestHandler_19bce9b1395c.handlePageRender(Unknown Source)
      at $ComponentRequestHandler_19bce9b1393f.handlePageRender(Unknown Source)
      at org.apache.tapestry5.internal.services.PageRenderDispatcher.dispatch(PageRenderDispatcher.java:45)
      at $Dispatcher_19bce9b13941.dispatch(Unknown Source)
      at $Dispatcher_19bce9b1393c.dispatch(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$RequestHandlerTerminator.service(TapestryModule.java:297)
      at com.example.newapp.services.AppModule$1.service(AppModule.java:90)
      at $RequestFilter_19bce9b1393b.service(Unknown Source)
      at $RequestHandler_19bce9b1393d.service(Unknown Source)
      at org.apache.tapestry5.internal.services.RequestErrorFilter.service(RequestErrorFilter.java:26)
      at $RequestHandler_19bce9b1393d.service(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$3.service(TapestryModule.java:894)
      at $RequestHandler_19bce9b1393d.service(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$2.service(TapestryModule.java:884)
      at $RequestHandler_19bce9b1393d.service(Unknown Source)
      at org.apache.tapestry5.internal.services.StaticFilesFilter.service(StaticFilesFilter.java:90)
      at $RequestHandler_19bce9b1393d.service(Unknown Source)
      at org.apache.tapestry5.internal.services.CheckForUpdatesFilter$2.invoke(CheckForUpdatesFilter.java:105)
      at org.apache.tapestry5.internal.services.CheckForUpdatesFilter$2.invoke(CheckForUpdatesFilter.java:95)
      at org.apache.tapestry5.ioc.internal.util.ConcurrentBarrier.withRead(ConcurrentBarrier.java:85)
      at org.apache.tapestry5.internal.services.CheckForUpdatesFilter.service(CheckForUpdatesFilter.java:119)
      at $RequestHandler_19bce9b1393d.service(Unknown Source)
      at $RequestHandler_19bce9b13930.service(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$HttpServletRequestHandlerTerminator.service(TapestryModule.java:248)
      at org.apache.tapestry5.internal.gzip.GZipFilter.service(GZipFilter.java:53)
      at $HttpServletRequestHandler_19bce9b13932.service(Unknown Source)
      at org.apache.tapestry5.internal.services.IgnoredPathsFilter.service(IgnoredPathsFilter.java:62)
      at $HttpServletRequestFilter_19bce9b1392f.service(Unknown Source)
      at $HttpServletRequestHandler_19bce9b13932.service(Unknown Source)
      at org.apache.tapestry5.services.TapestryModule$1.service(TapestryModule.java:844)
      at $HttpServletRequestHandler_19bce9b13932.service(Unknown Source)
      at $HttpServletRequestHandler_19bce9b1392d.service(Unknown Source)
      at org.apache.tapestry5.TapestryFilter.doFilter(TapestryFilter.java:160)
      at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1148)
      at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:387)
      at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
      at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
      at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
      at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)
      at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
      at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
      at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
      at org.mortbay.jetty.Server.handle(Server.java:324)
      at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:535)
      at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:865)
      at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)
      at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
      at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
      at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
      at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:520)
      Caused by: java.lang.RuntimeException: Unable to locate Method public void setupRender(): com.example.newapp.pages.ChildA.setupRender()
      at org.apache.tapestry5.internal.plastic.MethodInvocationBundle.findMethod(MethodInvocationBundle.java:63)
      at org.apache.tapestry5.internal.plastic.MethodInvocationBundle.getMethod(MethodInvocationBundle.java:42)
      at org.apache.tapestry5.internal.plastic.AbstractMethodInvocation.getMethod(AbstractMethodInvocation.java:110)
      at org.apache.tapestry5.ioc.internal.services.MethodLogger.entry(MethodLogger.java:63)
      at org.apache.tapestry5.ioc.internal.services.LoggingAdvice.advise(LoggingAdvice.java:41)
      at org.apache.tapestry5.internal.plastic.AbstractMethodInvocation.proceed(AbstractMethodInvocation.java:86)
      at com.example.newapp.base.Parent.setupRender(Parent.java)
      at com.example.newapp.base.Parent.setupRender(Parent.java)
      at org.apache.tapestry5.internal.structure.ComponentPageElementImpl$SetupRenderPhase.invokeComponent(ComponentPageElementImpl.java:174)
      at org.apache.tapestry5.internal.structure.ComponentPageElementImpl$AbstractPhase.invoke(ComponentPageElementImpl.java:133)
      ... 81 more
      Caused by: java.lang.NoSuchMethodException: com.example.newapp.pages.ChildA.setupRender()
      at java.lang.Class.getDeclaredMethod(Class.java:1954)
      at org.apache.tapestry5.internal.plastic.MethodInvocationBundle.findMethod(MethodInvocationBundle.java:59)
      ... 90 more

        Activity

        Sigbjørn Tvedt created issue -
        Howard M. Lewis Ship made changes -
        Field Original Value New Value
        Assignee Howard M. Lewis Ship [ hlship ]
        Hide
        Howard M. Lewis Ship added a comment -

        Making some progress here. I now understand what's causing it and why going to the second page makes it work.

        It all comes down to this code:

        public MethodInvocationBundle(MethodDescription methodDescription, MethodAdvice[] advice)

        { this.methodDescription = methodDescription; this.advice = advice; }

        public Method getMethod(Object instance)

        { if (method == null) method = findMethod(instance.getClass()); return method; }

        @SuppressWarnings("unchecked")
        private Method findMethod(Class clazz)
        {
        try
        {
        Class[] types = new Class[methodDescription.argumentTypes.length];

        for (int i = 0; i < types.length; i++)

        { types[i] = PlasticInternalUtils.toClass(clazz.getClassLoader(), methodDescription.argumentTypes[i]); }

        return clazz.getDeclaredMethod(methodDescription.methodName, types);
        }
        catch (Exception ex)

        { throw new RuntimeException(String.format("Unable to locate Method %s: %s", methodDescription, PlasticInternalUtils.toMessage(ex)), ex); }

        }

        This MethodInvocationBundle is created for the advice on the base class (Parent) implementation of setupRender().

        Here's the trick: if you invoke this for child A (which does not override the setupRender method), this code is invoked with clazz == ChildA and clazz.getDeclaredMethod() fails.

        Later, you invoke this for child B, which does override the method. getDeclaredMethod() succeeds, and the result is stored for later invocations for both ChildA and ChildB.

        The core of this is going to be: how to get clazz to be the right class (the parent class, not any of the child classes).

        Show
        Howard M. Lewis Ship added a comment - Making some progress here. I now understand what's causing it and why going to the second page makes it work. It all comes down to this code: public MethodInvocationBundle(MethodDescription methodDescription, MethodAdvice[] advice) { this.methodDescription = methodDescription; this.advice = advice; } public Method getMethod(Object instance) { if (method == null) method = findMethod(instance.getClass()); return method; } @SuppressWarnings("unchecked") private Method findMethod(Class clazz) { try { Class[] types = new Class [methodDescription.argumentTypes.length] ; for (int i = 0; i < types.length; i++) { types[i] = PlasticInternalUtils.toClass(clazz.getClassLoader(), methodDescription.argumentTypes[i]); } return clazz.getDeclaredMethod(methodDescription.methodName, types); } catch (Exception ex) { throw new RuntimeException(String.format("Unable to locate Method %s: %s", methodDescription, PlasticInternalUtils.toMessage(ex)), ex); } } This MethodInvocationBundle is created for the advice on the base class (Parent) implementation of setupRender(). Here's the trick: if you invoke this for child A (which does not override the setupRender method), this code is invoked with clazz == ChildA and clazz.getDeclaredMethod() fails. Later, you invoke this for child B, which does override the method. getDeclaredMethod() succeeds, and the result is stored for later invocations for both ChildA and ChildB. The core of this is going to be: how to get clazz to be the right class (the parent class, not any of the child classes).
        Howard M. Lewis Ship made changes -
        Status Open [ 1 ] Closed [ 6 ]
        Fix Version/s 5.3 [ 12316024 ]
        Resolution Fixed [ 1 ]
        Hide
        Hudson added a comment -

        Integrated in tapestry-trunk-freestyle #535 (See https://builds.apache.org/job/tapestry-trunk-freestyle/535/)
        TAP5-1656: Search for methods in the class they are defined in, which may not be the same as the instance class
        TAP5-1656: Enable logging, to trigger the error
        TAP5-1656: Introduce test case to reproduce bug

        So far, does not reproduce

        hlship : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1174848
        Files :

        • /tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodAdviceManager.java
        • /tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodInvocationBundle.java
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ClassTransformationTests.groovy
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildA.tml
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildB.tml

        hlship : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1174847
        Files :

        • /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties

        hlship : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1174846
        Files :

        • /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/InheritBase.java
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/inherit
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/inherit/ChildA.java
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/inherit/ChildB.java
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildA.tml
        • /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildB.tml
        Show
        Hudson added a comment - Integrated in tapestry-trunk-freestyle #535 (See https://builds.apache.org/job/tapestry-trunk-freestyle/535/ ) TAP5-1656 : Search for methods in the class they are defined in, which may not be the same as the instance class TAP5-1656 : Enable logging, to trigger the error TAP5-1656 : Introduce test case to reproduce bug So far, does not reproduce hlship : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1174848 Files : /tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodAdviceManager.java /tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodInvocationBundle.java /tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ClassTransformationTests.groovy /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildA.tml /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildB.tml hlship : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1174847 Files : /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties hlship : http://svn.apache.org/viewcvs.cgi/?root=Apache-SVN&view=rev&rev=1174846 Files : /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/base/InheritBase.java /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/inherit /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/inherit/ChildA.java /tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/inherit/ChildB.java /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildA.tml /tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/inherit/ChildB.tml

          People

          • Assignee:
            Howard M. Lewis Ship
            Reporter:
            Sigbjørn Tvedt
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development