2

While coding, I spotted that replacing a lambda with a perfectly fine (IMO) method reference results in a compilation error using openJDK 17.

Investigation of the case led me to creating a minimal example of the code, that does not work in compilers that I found on my PC:

import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;

class ExampleTest {
    public static void main(String[] args) {
        SessionContext sessionContext = new SessionContext();
        Entity foo = new Entity(null, "foo");

        Optional<Long> id = sessionContext.get(session -> {
            return Stream.of(foo)
                    .map(entity -> insert(entity, session))
                    .map(Entity::getId)
                    .findAny();
        });

        System.out.println(id);
    }


    static Entity insert(Entity entity, Session session) {
        return session.persist(entity);
    }
}

class Session {
    Entity persist(Entity entity) {
        entity.setId(42L);
        return entity;
    }
}

class SessionContext {
    Session session = new Session();

    <T> T get(Function<Session, T> query) {
        return query.apply(session);
    }
}

class Entity {
    private Long id;
    private String data;

    Entity(Long id, String data) {
        this.id = id;
        this.data = data;
    }

    Long getId() {
        return id;
    }

    void setId(Long id) {
        this.id = id;
    }
}

As far as I checked, the code compiles on openJDK 8. It does not compile on the following JVMs:

  • openJDK 17;
  • zulu16;
  • zulu17;
  • oracle 18.

Error displayed by the compilers:

ExampleTest.java:13: error: incompatible types: invalid method reference
                    .map(Entity::getId)
                         ^
    method getId in class Entity cannot be applied to given types
      required: no arguments
      found:    Object
      reason: actual and formal argument lists differ in length
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output

There are other quirks too. If you follow the hint in the message above and use -Xdiags:verbose... The compilation will automagically pass!

Please note that:

  • The code example itself might not make much sense, it is just to illustrate the point in the most clear way.
  • There can be a lot of refactorings done to the example code, but as far as I checked, they ultimately lead to not getting the compilation error.

Has anyone observed similar behavior? Does anyone recall if it is an official compilator error? Or maybe I am missing something in the code?

I expected this code to compile on all JVM as it looks OK.

  • The Stream.map call in question expects a function that takes one parameter of type Entity and returns a value of type Long. Entity.getId does not take any parameters. – Thomas Behr Dec 06 '22 at 16:34
  • @ThomasBehr Entity.getId does not take any parameters, but it is a method in class Entity, which makes it a perfect candidate for a method reference. Please check https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html -> Kinds of Method References -> Reference to an instance method of a particular object. If this was not true, you would not be able to perform eg.: `Stream.of("abc").map(String::toUpperCase)` – karolkoltundev Dec 06 '22 at 16:40
  • 1
    Clearly a javac bug. All those alternate JDKs you named don't also provide an alternate javac impl, they just use the same one, so they'd trivially fail as well and there is no point filing bugs with them - the right place to file the bug is with javac itself. – rzwitserloot Dec 06 '22 at 16:43
  • 1
    A compilation error that goes away when using `-Xdiags:verbose`… that rings a bell. See [JDK-8268312](https://bugs.openjdk.org/browse/JDK-8268312), supposed to be fixed in JDK 20. There are also the duplicates [JDK-8295988](https://bugs.openjdk.org/browse/JDK-8295988) and [JDK-8282705](https://bugs.openjdk.org/browse/JDK-8282705) – Holger Dec 07 '22 at 17:47
  • 1
    Found the reason why I remembered the issue: https://stackoverflow.com/q/73704260/2711488 Especially [this comment of mine](https://stackoverflow.com/questions/73704260/method-in-class-string-cannot-be-applied-to-given-types-when-replacing-lambda-wi#comment130170084_73715098) Decide yourself whether it’s a duplicate… – Holger Dec 07 '22 at 17:53

0 Answers0