I think I found the issue.
Not 100% sure yet, but my first tests look good.

The PropertyShadowBuilder got changed in TAP5-2582, so it can handle
duplicate methods if interfaces extend each other.


In the case of Session, however, the return types of the methods differ, as
it's totally valid to elevate a return type if you extend an interface, as
long as the new return type extends/implements the previous one.
The
org.apache.tapestry5.ioc.internal.services.PropertyShadowBuilderImpl.MethodSignatureUniqueComparator
is used for sorting the methods, so only the first of each method is used.


For example,without checking the return type, the method

public abstract org.hibernate.query.Query
org.hibernate.SharedSessionContract.getNamedQuery(java.lang.String)

gets removed.



With comparing return types, the method

public default org.hibernate.Query
org.hibernate.SharedSessionContract.getNamedQuery(java.lang.String)

gets removed.


What confused me was the "default" modifier on the method, as the method
declarations in the interface don't have a "default" implementations.
Let's recreate the scenario:

interface Original {
    Number test();
}
interface Extended extends Original {
    Double test();
}

Time for some bytecode:

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"

Ok, the "default" method now makes more sense, as the two methods exist on
the interface but with different return types.
This might feel like invalid Java, as the return type doesn't count to the
method signature, but the JVM allows that.
The ACC_BRIDGE flag means that the method was generated by the compiler to
"bridge" between the original method declaration and the override.


With that knowledge, my hunch is that even though the default method, which
should call the correct method, can't because, well, Proxies do a lot of
bytecode magic themselves.


On Fri, Jun 23, 2023 at 8:22 PM Vangel V. Ajanovski <ajanov...@gmail.com>
wrote:

> On 21.6.23 20:32, Volker Lamp wrote:
> > Is there any chance I can motivate you to contribute your test case as
> > a unit test to the Tapestry code base? Have a look at the test apps in
> > tapestry-jpa as a starting point.
>
> If I find some free time in the following months to look it up and learn
> how to create an entire test case. For the time-being it will be faster
> for me to create a docker container spec to reproduce the bug.
>
> As an alternative, I tried to modify the tapestry sources and the
> existing tests. I have never tried to build tapestry from source in the
> past, so bare with my ignorance. I cloned the sources from git, and
> decided for the command line route and just did ./gradlew build.
>
> It seems successful. All the .jars are at the expected locations. I
> modified the gradle build file and hibernate.cfg.xml in the test folders
> inside tapestry-hibernate so that it should connect to another database
> and it uses another driver, just to see if this will stir things up, but
> nothing happened. The problem is that I don't see any connections to the
> database when I run the build, which seems strange to me. How do I force
> the tests to rerun and which is the specific test that i should run that
> uses the connection information in
> tapestry-hibernate/src/test/resources/hibernate.cfg.xml?
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
> For additional commands, e-mail: users-h...@tapestry.apache.org
>
>

Reply via email to