Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda/default methods/type erasure quirk/bug using ECJ?

Came accross this today and spent ages trying to reproduce/figure out what was happening. Can somebody explain why this happens or is this a bug with type erasure/default methods/lambda's/polymorphism? Uncommenting the default method makes it run fine, but I would have expected this to work as is

Output:

Works fine with an object
Calling consume
Hello
Calling accept with context
Hello
Calling accept via consumer...
Exception in thread "main" java.lang.AbstractMethodError: Method test/LambdaTest$$Lambda$1.accept(Ljava/lang/Object;)V is abstract
    at test.LambdaTest$$Lambda$1/834600351.accept(Unknown Source)
    at test.LambdaTest.main(LambdaTest.java:24)

Code

package test;

import java.util.function.Consumer;

public class LambdaTest {

    public static void main(String[] args) {
        Consumer<Context> contextIgnoringObject = new ContextUnawareObject();
        contextIgnoringObject.accept(new Context());

        ContextIgnorer contextIgnoringLambda = () -> {
            System.err.println("Hello");
        };

        System.err.println("Calling consume");
        contextIgnoringLambda.consume();

        System.err.println("Calling accept with context");
        contextIgnoringLambda.accept(new Context());

        Consumer<Context> consumer = contextIgnoringLambda;

        System.err.println("Calling accept via consumer...");
        consumer.accept(new Context());

    }

    @FunctionalInterface
    public interface ContextIgnorer extends Consumer<Context> {

//      default void accept(Object object) {
//          System.err.println("Manual bridge method");
//          accept((Context)object);
//      }

        @Override
        default void accept(Context context) {
            consume();
        }

        void consume();

    }

    public static class ContextUnawareObject implements ContextIgnorer {

        @Override
        public void consume() {
            System.err.println("Works fine with an object");
        }

    }

    public static class Context {

    }

}
like image 601
vincent_ Avatar asked Nov 09 '22 10:11

vincent_


1 Answers

The problem appears with older ECJ compiler (3.10.0):

$ java -jar org.eclipse.jdt.core-3.10.0.v20140604-1726.jar -source 1.8 LambdaTest.java 
$ java LambdaTest
Works fine with an object
Calling consume
Hello
Calling accept with context
Hello
Calling accept via consumer...
Exception in thread "main" java.lang.AbstractMethodError: Method LambdaTest$$Lambda$1.accept(Ljava/lang/Object;)V is abstract
    at LambdaTest$$Lambda$1/424058530.accept(Unknown Source)
    at LambdaTest.main(LambdaTest.java:24)

Using org.eclipse.jdt.core_3.10.0.v20140902-0626.jar or newer solves the problem. The Oracle javac compiler has no such problem. Thus the solution would be to update your ECJ compiler or move to the javac.

like image 176
Tagir Valeev Avatar answered Nov 15 '22 11:11

Tagir Valeev