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 Bug
    • Status: Closed
    • Priority: Major 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
        Howard M. Lewis Ship added a comment -

        This time for sure!

        Show
        Howard M. Lewis Ship added a comment - This time for sure!
        Hide
        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
        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
        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
        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
        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
        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
        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
        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
        Massimo Lusetti added a comment -

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

        Show
        Massimo Lusetti added a comment - Would you like to elaborate a little more on what you are meaning by install? Thanks.
        Hide
        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
        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.

          People

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

            Dates

            • Created:
              Updated:
              Resolved:

              Development