[ 
https://issues.apache.org/jira/browse/TAP5-2754?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17736751#comment-17736751
 ] 

Ben Weidig commented on TAP5-2754:
----------------------------------

Further investigation lead me down the road how PropertyShadowBuilder chooses 
methods to shadow.

In the case of interfaces that extend methods with different return types, the 
duplicate methods must be removed.

For example:
{code:java}
interface Original {
    Number test();
}
interface Extended extends Original {
    Double test();
}
{code}
will actually generate two methods in {{{}Extended{}}} as you can see from the 
bytecode:

{code}
Classfile /Users/ben/code/tapestry/tapestry-5/Extended.class
  Last modified 24 Jun 2023; size 254 bytes
  SHA-256 checksum 
708c3793a9074f5afdd523542cf287559d5cbeee871a0ca9757444dc28edafe3
  Compiled from "Extended.java"
interface Extended extends Original
  minor version: 0
  major version: 61
  flags: (0x0600) ACC_INTERFACE, ACC_ABSTRACT
  this_class: #2                          // Extended
  super_class: #7                         // java/lang/Object
  interfaces: 1, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = InterfaceMethodref #2.#3          // Extended.test:()Ljava/lang/Double;
   #2 = Class              #4             // Extended
   #3 = NameAndType        #5:#6          // test:()Ljava/lang/Double;
   #4 = Utf8               Extended
   #5 = Utf8               test
   #6 = Utf8               ()Ljava/lang/Double;
   #7 = Class              #8             // java/lang/Object
   #8 = Utf8               java/lang/Object
   #9 = Class              #10            // Original
  #10 = Utf8               Original
  #11 = Utf8               ()Ljava/lang/Number;
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               SourceFile
  #15 = Utf8               Extended.java
{
  public abstract java.lang.Double test();
    descriptor: ()Ljava/lang/Double;
    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT

  public default java.lang.Number test();
    descriptor: ()Ljava/lang/Number;
    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokeinterface #1,  1            // InterfaceMethod 
test:()Ljava/lang/Double;
         6: areturn
      LineNumberTable:
        line 1: 0
}
SourceFile: "Extended.java"
{code}

 The {{ACC_BRIDGE}} method is used to call the actual method from {{Extended}}.

As the {{Method[]}} from a {{Class#getMethods()}} call are neither sorted nor 
in any particular order, as stated in the javadoc, we sort the methods and 
remove duplicates by taking the first one.
If the return types don't differ, or the changed return type is first, that's 
fine.
In case of {{Session}}, however, the removed method differs if we look at the 
return type, too.

That's why I suspect that even though it should work, as the other method just 
calls the right one, in the case of a proxy, it doesn't work, as the Proxy does 
bytecode magic itself.



> Some methods of an injected Hibernate Session return null
> ---------------------------------------------------------
>
>                 Key: TAP5-2754
>                 URL: https://issues.apache.org/jira/browse/TAP5-2754
>             Project: Tapestry 5
>          Issue Type: Bug
>          Components: tapestry-hibernate
>    Affects Versions: 5.7.2, 5.8.2
>            Reporter: Ben Weidig
>            Assignee: Ben Weidig
>            Priority: Major
>
> If you inject the Hibernate Session, some calls might return null.
> Identified problematic methods are:
>  * createNativeQuery
>  * createQuery
>  * getNamedQuery
> It possible that more methods are affected.
> Debugging the issue is complicated, as the Hibernate Session is hidden away 
> behind a PropertyShadowBuilder.
> It's a property on org.apache.tapestry5.hibernate.HibernateSessionManager 
> that is created in 
> org.apache.tapestry5.hibernate.modules.HibernateCoreModule.buildSession(HibernateSessionManager,
>  PropertyShadowBuilder)
> The reasoning for this is that the Session doesn't have to be scoped 
> PerThread, as the HibernateSessionManager is, and the Session is only 
> actually created on first use, not on HSM creation.
> I've debugged through the shadowing process and checked the created 
> PlasticClass and underlying ClassNode, and they look good to me as all 
> methods are there.
> As everything is runtime-generated bytecode, maybe a tool like 
> [https://github.com/AdoptOpenJDK/jitwatch] could help to analyze what's 
> actually happening.
> My guess is that the big changes starting Hibernate 5.2 (moving towards 
> javax.persistence, like Session now extending javax.persistence.EntityManager 
> and org.hibernate.jpa.HibernateEntityManage) are not 100% compatible with 
> what Plastic/PropertyShadowBuilder are doing behind the scenes.
> It's not completely broken, but certain things seem to work a little 
> differently.
>  
> *Current workaround:*
> Call {{getSession()}} on the injected Session, the method will then work as 
> intended.
>  
> *Maybe related ticket:*
> https://issues.apache.org/jira/browse/TAP5-2582
>  
> *Related mailing list threads:*
> [https://lists.apache.org/thread/r4bhr01d95kpl8pslrhr1bdx486b29nd]
> [https://lists.apache.org/thread/qwc6430qq0f4nt7oc755z443c2zh6j68]
>  
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to