Uploaded image for project: 'Tapestry'
  1. Tapestry
  2. TAPESTRY-1423

Tapestry IoC fails to get the correct class from javassist.CtClass when the instance is already a proxy

    Details

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

      Description

      Using tapestry-spring to wire spring beans and have spring (I'm using 2.x) deal with hibernate entities and transaction management by AoP result in having entities being a proxy class.
      This cause, for example, the BeanEditForm to fail:

      1. java.lang.RuntimeException
        Unable to add method java.lang.Object get(java.lang.Object) to class $PropertyConduit_11214ae4ca6: [source error] no such class: it.datacode.tapestry.t5js.entities.Clients$$EnhancerByCGLIB$$4429b0f8
      2. javassist.CannotCompileException
        [source error] no such class: it.datacode.tapestry.t5js.entities.Clients$$EnhancerByCGLIB$$4429b0f8

      reason
      [source error] no such class: it.datacode.tapestry.t5js.entities.Clients$$EnhancerByCGLIB$$4429b0f8

      1. javassist.compiler.CompileError
        no such class: it.datacode.tapestry.t5js.entities.Clients$$EnhancerByCGLIB$$4429b0f8

      Stack trace

      • javassist.compiler.MemberResolver.searchImports(MemberResolver.java:416)
      • javassist.compiler.MemberResolver.lookupClass(MemberResolver.java:392)
      • javassist.compiler.MemberResolver.lookupClassByJvmName(MemberResolver.java:310)
      • javassist.compiler.MemberResolver.resolveJvmClassName(MemberResolver.java:460)
      • javassist.compiler.MemberCodeGen.resolveClassName(MemberCodeGen.java:1064)
      • javassist.compiler.CodeGen.atDeclarator(CodeGen.java:698)
      • javassist.compiler.ast.Declarator.accept(Declarator.java:99)
      • javassist.compiler.CodeGen.atStmnt(CodeGen.java:344)
      • javassist.compiler.ast.Stmnt.accept(Stmnt.java:49)
      • javassist.compiler.CodeGen.atStmnt(CodeGen.java:344)
      • javassist.compiler.ast.Stmnt.accept(Stmnt.java:49)
      • javassist.compiler.CodeGen.atMethodBody(CodeGen.java:285)
      • javassist.compiler.Javac.compileBody(Javac.java:212)
      • javassist.CtBehavior.setBody(CtBehavior.java:340)
      • javassist.CtBehavior.setBody(CtBehavior.java:315)
      • org.apache.tapestry.ioc.internal.services.ClassFabImpl.addMethod(ClassFabImpl.java:218)
      • org.apache.tapestry.internal.services.PropertyConduitSourceImpl.buildGetter(PropertyConduitSourceImpl.java:227)
      • org.apache.tapestry.internal.services.PropertyConduitSourceImpl.build(PropertyConduitSourceImpl.java:114)
      • org.apache.tapestry.internal.services.PropertyConduitSourceImpl.create(PropertyConduitSourceImpl.java:75)
      • org.apache.tapestry.internal.beaneditor.BeanModelImpl.createConduit(BeanModelImpl.java:83)
      • org.apache.tapestry.internal.beaneditor.BeanModelImpl.add(BeanModelImpl.java:67)
      • org.apache.tapestry.internal.services.BeanModelSourceImpl.create(BeanModelSourceImpl.java:95)
      • org.apache.tapestry.corelib.components.BeanEditForm.onPrepareFromForm(BeanEditForm.java:207)
      • org.apache.tapestry.corelib.components.BeanEditForm.handleComponentEvent(BeanEditForm.java)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl.handleEvent(ComponentPageElementImpl.java:895)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl.triggerEvent(ComponentPageElementImpl.java:1002)
      • org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.triggerEvent(InternalComponentResourcesImpl.java:141)
      • org.apache.tapestry.corelib.components.Form.beginRender(Form.java:223)
      • org.apache.tapestry.corelib.components.Form.beginRender(Form.java)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl$10$1.run(ComponentPageElementImpl.java:345)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl.invoke(ComponentPageElementImpl.java:940)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl.access$100(ComponentPageElementImpl.java:69)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl$10.render(ComponentPageElementImpl.java:349)
      • org.apache.tapestry.internal.services.RenderQueueImpl.run(RenderQueueImpl.java:57)
      • org.apache.tapestry.internal.services.PageMarkupRendererImpl.renderPageMarkup(PageMarkupRendererImpl.java:42)
      • org.apache.tapestry.internal.services.PageResponseRendererImpl.renderPageResponse(PageResponseRendererImpl.java:49)
      • org.apache.tapestry.internal.services.PageRenderDispatcher$1.renderPage(PageRenderDispatcher.java:82)
      • org.apache.tapestry.internal.services.PageLinkHandlerImpl.handle(PageLinkHandlerImpl.java:89)
      • org.apache.tapestry.internal.services.PageLinkHandlerImpl.handle(PageLinkHandlerImpl.java:49)
      • org.apache.tapestry.internal.services.PageRenderDispatcher.dispatch(PageRenderDispatcher.java:91)
      • org.apache.tapestry.services.TapestryModule$12.service(TapestryModule.java:1073)
      • it.datacode.tapestry.t5js.services.AppModule$1.service(AppModule.java:59)

      So when the ioc get the CtClass should try to obtain the actual name of the class discarding the proxy part.
      This patch, actually an hack, fix the problem:

      Index: src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java
      ===================================================================
      — src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java (revision 530468)
      +++ src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java (working copy)
      @@ -62,7 +62,9 @@
      public static String toJavaClassName(Class inputClass)

      { if (inputClass.isArray()) return toJavaClassName(inputClass.getComponentType()) + "[]"; - + else if (inputClass.getName().indexOf("$$") != -1) + return inputClass.getName().substring(0, inputClass.getName().indexOf('$')); + return inputClass.getName(); }

        Activity

        Hide
        hlship Howard M. Lewis Ship added a comment -

        I think I want to pursue a different fix, one in which we "install" the correct class loader that defines the proxy class, so that Javassist can see it. I should hit this same problem soon, once I do a little more on the tapestry-hibernate module.

        Show
        hlship Howard M. Lewis Ship added a comment - I think I want to pursue a different fix, one in which we "install" the correct class loader that defines the proxy class, so that Javassist can see it. I should hit this same problem soon, once I do a little more on the tapestry-hibernate module.
        Hide
        mlusetti Massimo Lusetti added a comment -

        Would you like to elaborate a little more on what you are meaning by install? Thanks.

        Show
        mlusetti Massimo Lusetti added a comment - Would you like to elaborate a little more on what you are meaning by install? Thanks.
        Hide
        mlusetti Massimo Lusetti added a comment -

        Conclusively this issue is caused by a call to the load(Class.class, id) method of the underlying hibernate session obtained within a DAO from the getCurrentSession method of the Hibernate sessionFactory instance.

        Changing the load method call from load to get (same signature) the issue vanished.

        Show
        mlusetti Massimo Lusetti added a comment - Conclusively this issue is caused by a call to the load(Class.class, id) method of the underlying hibernate session obtained within a DAO from the getCurrentSession method of the Hibernate sessionFactory instance. Changing the load method call from load to get (same signature) the issue vanished.
        Hide
        hlship Howard M. Lewis Ship added a comment -

        I've been working on a fix.

        For this kind of class, there's no bytecode in a JAR or on the filesystem to read. That's primarily what's tripping up Javassist.

        What I've coded is a mechanism to work up the inheritance hiearchy until a useable class is located.

        This should fix the Hibernate case (the proxy is a subclass of the real entity class, for which bytecode is available). I'll set up a hibernate case before closing the bug.

        Show
        hlship Howard M. Lewis Ship added a comment - I've been working on a fix. For this kind of class, there's no bytecode in a JAR or on the filesystem to read. That's primarily what's tripping up Javassist. What I've coded is a mechanism to work up the inheritance hiearchy until a useable class is located. This should fix the Hibernate case (the proxy is a subclass of the real entity class, for which bytecode is available). I'll set up a hibernate case before closing the bug.
        Hide
        hlship Howard M. Lewis Ship added a comment -

        The snapshot has been out there for a while, I see that people have been using tapestry-hibernate, I think this is now fixed.

        Show
        hlship Howard M. Lewis Ship added a comment - The snapshot has been out there for a while, I see that people have been using tapestry-hibernate, I think this is now fixed.
        Hide
        hlship Howard M. Lewis Ship added a comment -

        Found another variation of this bug:

        org.apache.tapestry.ioc.internal.util.TapestryException
        Unable to lookup class
        com.crimsonata.billing.entities.CreditCardInfo$$EnhancerByCGLIB$$4fc9dc60:
        com.crimsonata.billing.entities.CreditCardInfo$$EnhancerByCGLIB$$4fc9dc60

        Here's some stack trace:

        javassist.NotFoundException
        com.crimsonata.billing.entities.CreditCardInfo$$EnhancerByCGLIB$$4fc9dc60

        Stack trace

        • javassist.ClassPool.get(ClassPool.java:417)
        • org.apache.tapestry.ioc.internal.services.CtClassSource.getCtClass(CtClassSource.java:65)
        • org.apache.tapestry.ioc.internal.services.ClassFactoryImpl.getMethodLocation(ClassFactoryImpl.java:130)
        • org.apache.tapestry.internal.TapestryInternalUtils.orderProperties(TapestryInternalUtils.java:394)
        • org.apache.tapestry.internal.services.BeanModelSourceImpl.create(BeanModelSourceImpl.java:102)
        • org.apache.tapestry.corelib.components.BeanEditForm.onPrepareFromForm(BeanEditForm.java:253)
        • org.apache.tapestry.corelib.components.BeanEditForm.handleComponentEvent(BeanEditForm.java)
        • org.apache.tapestry.internal.structure.ComponentPageElementImpl.handleEvent(ComponentPageElementImpl.java:885)
        • org.apache.tapestry.internal.structure.ComponentPageElementImpl.triggerEvent(ComponentPageElementImpl.java:998)
        • org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.triggerEvent(InternalComponentResourcesImpl.java:147)
        • org.apache.tapestry.corelib.components.Form.beginRender(Form.java:227)
        • org.apache.tapestry.corelib.components.Form.beginRender(Form.java)
        • org.apache.tapestry.internal.structure.ComponentPageElementImpl$10$1.run(ComponentPageElementImpl.java:345)
        • org.apache.tapestry.internal.structure.ComponentPageElementImpl.invoke(ComponentPageElementImpl.java:931)
        • org.apache.tapestry.internal.structure.ComponentPageElementImpl.access$100(ComponentPageElementImpl.java:69)
        • org.apache.tapestry.internal.structure.ComponentPageElementImpl$10.render(ComponentPageElementImpl.java:349)
        • org.apache.tapestry.internal.services.RenderQueueImpl.run(RenderQueueImpl.java:57)
        • org.apache.tapestry.internal.services.PageMarkupRendererImpl.renderPageMarkup(PageMarkupRendererImpl.java:40)
        • org.apache.tapestry.internal.services.PageResponseRendererImpl.renderPageResponse(PageResponseRendererImpl.java:45)
        • org.apache.tapestry.internal.services.PageRenderDispatcher$1.renderPage(PageRenderDispatcher.java:82)
        • org.apache.tapestry.internal.services.PageLinkHandlerImpl.handle(PageLinkHandlerImpl.java:89)
        • org.apache.tapestry.internal.services.PageLinkHandlerImpl.handle(PageLinkHandlerImpl.java:49)
        • org.apache.tapestry.internal.services.PageRenderDispatcher.dispatch(PageRenderDispatcher.java:91)
        • org.apache.tapestry.services.TapestryModule$12.service(TapestryModule.java:1061)
        • com.crimsonata.billing.services.AppModule$1.service(AppModule.java:64)

        So, it's been fixed for the PropBindingFactory, but not for the BeanModelSource.

        Show
        hlship Howard M. Lewis Ship added a comment - Found another variation of this bug: org.apache.tapestry.ioc.internal.util.TapestryException Unable to lookup class com.crimsonata.billing.entities.CreditCardInfo$$EnhancerByCGLIB$$4fc9dc60: com.crimsonata.billing.entities.CreditCardInfo$$EnhancerByCGLIB$$4fc9dc60 Here's some stack trace: javassist.NotFoundException com.crimsonata.billing.entities.CreditCardInfo$$EnhancerByCGLIB$$4fc9dc60 Stack trace javassist.ClassPool.get(ClassPool.java:417) org.apache.tapestry.ioc.internal.services.CtClassSource.getCtClass(CtClassSource.java:65) org.apache.tapestry.ioc.internal.services.ClassFactoryImpl.getMethodLocation(ClassFactoryImpl.java:130) org.apache.tapestry.internal.TapestryInternalUtils.orderProperties(TapestryInternalUtils.java:394) org.apache.tapestry.internal.services.BeanModelSourceImpl.create(BeanModelSourceImpl.java:102) org.apache.tapestry.corelib.components.BeanEditForm.onPrepareFromForm(BeanEditForm.java:253) org.apache.tapestry.corelib.components.BeanEditForm.handleComponentEvent(BeanEditForm.java) org.apache.tapestry.internal.structure.ComponentPageElementImpl.handleEvent(ComponentPageElementImpl.java:885) org.apache.tapestry.internal.structure.ComponentPageElementImpl.triggerEvent(ComponentPageElementImpl.java:998) org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.triggerEvent(InternalComponentResourcesImpl.java:147) org.apache.tapestry.corelib.components.Form.beginRender(Form.java:227) org.apache.tapestry.corelib.components.Form.beginRender(Form.java) org.apache.tapestry.internal.structure.ComponentPageElementImpl$10$1.run(ComponentPageElementImpl.java:345) org.apache.tapestry.internal.structure.ComponentPageElementImpl.invoke(ComponentPageElementImpl.java:931) org.apache.tapestry.internal.structure.ComponentPageElementImpl.access$100(ComponentPageElementImpl.java:69) org.apache.tapestry.internal.structure.ComponentPageElementImpl$10.render(ComponentPageElementImpl.java:349) org.apache.tapestry.internal.services.RenderQueueImpl.run(RenderQueueImpl.java:57) org.apache.tapestry.internal.services.PageMarkupRendererImpl.renderPageMarkup(PageMarkupRendererImpl.java:40) org.apache.tapestry.internal.services.PageResponseRendererImpl.renderPageResponse(PageResponseRendererImpl.java:45) org.apache.tapestry.internal.services.PageRenderDispatcher$1.renderPage(PageRenderDispatcher.java:82) org.apache.tapestry.internal.services.PageLinkHandlerImpl.handle(PageLinkHandlerImpl.java:89) org.apache.tapestry.internal.services.PageLinkHandlerImpl.handle(PageLinkHandlerImpl.java:49) org.apache.tapestry.internal.services.PageRenderDispatcher.dispatch(PageRenderDispatcher.java:91) org.apache.tapestry.services.TapestryModule$12.service(TapestryModule.java:1061) com.crimsonata.billing.services.AppModule$1.service(AppModule.java:64) So, it's been fixed for the PropBindingFactory, but not for the BeanModelSource.
        Hide
        hlship Howard M. Lewis Ship added a comment -

        This time for sure!

        Show
        hlship Howard M. Lewis Ship added a comment - This time for sure!

          People

          • Assignee:
            hlship Howard M. Lewis Ship
            Reporter:
            mlusetti Massimo Lusetti
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development