Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8042404

Method references are broken with method that returns a generic type

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Cannot Reproduce
    • Affects Version/s: 8
    • Fix Version/s: 9
    • Component/s: tools
    • Labels:
    • Subcomponent:
    • CPU:
      x86_64
    • OS:
      windows_7

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.8.0"
        Java(TM) SE Runtime Environment (build 1.8.0-b132)
        Java HotSpot(TM) Client VM (build 25.0-b70, mixed mode, sharing)


        ADDITIONAL OS VERSION INFORMATION :
        Windows 7 64 bits, Windows 8.1 64 bits

        A DESCRIPTION OF THE PROBLEM :
        Method references cannot be used with method taht returns generic type.

        ^^^^^^^^^^^^
        getObject()::doSomething

        The getObject could not be resolved if it returns a generic type

        When a parent class defines a generic type with a getter.
        This getter cannot be called from a child class with a method reference.

        Althought if we create a new getter with the right forced type the method is correctly called.

        Provided sample code reproduced the problem

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run TestFailure class

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The handler defined into AbstractClass is correctly resolved and called

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
        Exception Details:
          Location:
            TestFailure.main([Ljava/lang/String;)V @13: invokedynamic
          Reason:
            Type 'Handler' (current frame, stack[1]) is not assignable to 'CustomHandler'
          Current Frame:
            bci: @13
            flags: { }
            locals: { '[Ljava/lang/String;', 'ConcreteClass' }
            stack: { 'ConcreteClass', 'Handler' }
          Bytecode:
            0000000: bb00 1059 b700 124c 2b2b b600 13ba 001a
            0000010: 0000 b600 1b2b b600 1fb1

        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2688)
        at java.lang.Class.getMethod0(Class.java:2937)
        at java.lang.Class.getMethod(Class.java:1771)
        at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        // Define the generic handler
        public abstract class AbstractClass <H extends Handler >{

        private H parentHandler;

        public AbstractClass(H parentHandler) {
        super();
        this.parentHandler = parentHandler;
        }

        public H getHandler() {
        return parentHandler;
        }
        }

        //Call the generic handler
        public class ConcreteClass extends AbstractClass<CustomHandler> {

        private Handler localHandler;

        public ConcreteClass() {
        //Define parentHandler
        super(new CustomHandler());
        }

        public void setLocalHandler(Handler handler){
        this.localHandler = handler;
        }

        public CustomHandler getForcedHandler() {
        //return the parent handler
        return getHandler();
        }

        public void check() {
        localHandler.handle(new Object());
        }
        }

        @FunctionalInterface
        public interface Handler {
        void handle(Object o);
        }

        public class CustomHandler implements Handler {
        @Override
        public void handle(Object o) {
        System.out.println("It works !");
        }
        }

        public class TestFailure {

        public static void main (String... arg){

        ConcreteClass cc = new ConcreteClass();

        //Grab the parent handler
                        // ^^^^^^^^^^^^^^
        cc.setLocalHandler(cc.getHandler()::handle);

        //Try to handle ==> fails
        cc.check();

        }
        }

        public class TestWorkaround {


        public static void main (String... arg){

        ConcreteClass cc = new ConcreteClass();

        //Grab the parent handler
                        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        cc.setLocalHandler(cc.getForcedHandler()::handle);

        //Try to handle ==> Success due to getForcedHandler() method with static type
        cc.check();

        }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        Create a method that returns a static type instead of the generic one returned by parent class

        public CustomHandler getForcedHandler() {
        //return the parent handler
        return getHandler();
        }

          Attachments

            Issue Links

              Activity

                People

                Assignee:
                rfield Robert Field
                Reporter:
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                  Dates

                  Created:
                  Updated:
                  Resolved: