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

Inconsistent compilation of method references vs identical lambdas

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      ADDITIONAL SYSTEM INFORMATION :
      Linux Mint 21.3, Adoptium 21.0.2

      A DESCRIPTION OF THE PROBLEM :
      When developing a custom library that utilizes Spring's WebClient, I encountered a weird issue with generics which involves a family of interfaces described in Spring's WebClient class. In short, source file would not compile if a method reference is used, but will compile just fine if that method reference was replaced with an identical lambda. To avoid complicating things, I've thrown together a minimal reproducible example which mimics the interface hierarchy of WebClient and illustrates the issue

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Compile the attached source code with a simple javac <path/to/file.java>
      2. Observe that it compiles without issues
      3. In the main method, comment out the line with a lambda and uncomment the line with a method reference
      4. Compile the file again with a simple javac <path/to/file.java>

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Source file compiles without issues
      ACTUAL -
      The following error is reported:

      <path/to/file.java>:24: error: method invoke in class ReproducibleExample cannot be applied to given types;
              invoke(Receiver::getRootWithExtra);
              ^
        required: Function<? super Receiver,? extends ES>
        found: Receiver::[...]Extra
        reason: inferred type does not conform to equality constraint(s)
          inferred: S#2
          equality constraints(s): CAP#1
        where ES,S#1,S#2 are type-variables:
          ES extends RootWithExtraInterface<S#1> declared in method <S#1,ES>invoke(Function<? super Receiver,? extends ES>)
          S#1 extends RootInterface<S#1> declared in method <S#1,ES>invoke(Function<? super Receiver,? extends ES>)
          S#2 extends RootInterface<S#2>
        where CAP#1 is a fresh type-variable:
          CAP#1 extends RootInterface<CAP#1> from capture of ?
      1 error


      ---------- BEGIN SOURCE ----------
      import java.util.function.Function;

      public class ReproducibleExample {
          // Stand-in for WebClient
          private interface Receiver {
              // Stand-in for get() (or any other method with the same return type)
              RootWithExtraInterface<?> getRootWithExtra();
          }
          // Stand-in for RequestHeadersSpec
          private interface RootInterface<S extends RootInterface<S>> {}
          // Stand-in for UriSpec
          private interface ExtraInterface<S extends RootInterface<?>> {}
          // Stand-in for RequestHeadersUriSpec
          private interface RootWithExtraInterface<S extends RootInterface<S>> extends RootInterface<S>, ExtraInterface<S> {}

          private static <S extends RootInterface<S>, ES extends RootWithExtraInterface<S>> S invoke(
                  Function<? super Receiver, ? extends ES> function
          ) {
              return null;
          }

          public static void main(String[] args) {
              invoke(receiver -> receiver.getRootWithExtra());
      // invoke(Receiver::getRootWithExtra);
          }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      Using lambda instead of a method reference and staring at a yellow wavy-line in your IDE which prompts you to convert it to a method reference.

      FREQUENCY : always


      Attachments

        Activity

          People

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated: