Visitar URL original
Cannot override default methods of indirect superinterfaces in Java 25. · Issue #400 · jython/jython · GitHub
Skip to content

Cannot override default methods of indirect superinterfaces in Java 25. #400

Description

@alexgobbo

Up to Java 24 we can override default members of both direct and indirect superinterfaces.

As example, these classes in Java:

 public interface A {
   default String getValue() {
       return "1";
   }
 } 
 public interface B extends A {
 }

Can be extended in Jython:

 class X(A):
      def getValue(self):        
           return "2"
 class Y(B):
      def getValue(self):        
           return "3"

In Java 25 the JVM allows invokespecial on a default method only if that interface is a direct superinterface.

Therefore the class X above works, but when I try to evaluate class Y I get:
java.lang.VerifyError: Bad invokespecial instruction: interface method to invoke is not in a direct superinterface.

As a workaround, I can inherit the base interface explicitly too:

 class Y(B, A):
      def getValue(self):        
           return "3"

But a proper fix in Jython would be greatly appreciated.

Activity

  1. wfouche commented on Mar 7, 2026

    @wfouche
    Member

    Java 25 test program.

    package org.example;
    
    interface A {
        default String getValue() {
            return "1";
        }
    } 
    
    interface B extends A {}
    
    class X implements A {
        public String getValue() {
            return "2";
        }
    }
    
    class Y implements B {
        public String getValue() {
            return "3";
        }
    }
    
    public class Java25 {
        public static void main(String[] args) {
            X x = new X();
            System.out.println(x.getValue());
            Y y = new Y();
            System.out.println(y.getValue());
        }
    }
    2
    3
    
  2. wfouche commented on Mar 7, 2026

    @wfouche
    Member

    Flattening the interface graph also works (class Y implements A, B)

    package org.example;
    
    interface A {
        default String getValue() {
            return "1";
        }
    } 
    
    interface B extends A {}
    
    class X implements A {
        public String getValue() {
            return "2";
        }
    }
    
    class Y implements A, B {
        public String getValue() {
            return "3";
        }
    }
    
    public class Java25 {
        public static void main(String[] args) {
            X x = new X();
            System.out.println(x.getValue());
            Y y = new Y();
            System.out.println(y.getValue());
        }
    }
    2
    3
    
  3. Stewori commented on Mar 8, 2026

    @Stewori
    Member

    Maybe a solution would be to insert the flattened list of inherited interfaces on the fly when bytecode for the class is generated. I cannot work on this myself, but I can mentor and support the solution and review process if someone wants to solve this issue. I think the starting point for this solution idea is org.python.compiler.ClassFile, it has a method addInterface. Next step would be to check from where ClassFileis called and how interfaces are supplied. That point can be adjusted to add the whole interface list.

    Or is there a better approach entirely?

  4. jeff5 commented on Mar 25, 2026

    @jeff5
    Member

    I was surprised that Java would make such a change of semantics. I couldn't even find it in the release notes. But, if I have understood correctly, it is really the effect of a bug fix, so something that should never have been possible, and now isn't:
    https://bugs.openjdk.org/browse/JDK-8350029 and https://bugs.openjdk.org/browse/JDK-8026065 .

    We must be generating code for something that ought to be impossible. However, we're an implementation of Python, so I think the question is "what does this Python program mean", and how do we make it do that. Sorry, just scratching the surface of this but I thought the background might help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions