luontola / retrolambda

Backport of Java 8's lambda expressions to Java 7, 6 and 5

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Backporting a method reference to interface enum methods fails

lyubomyr-shaydariv opened this issue · comments

Hi,

Please consider the following code. A simple interface that associates a parameterized key with an object:

public interface IIdentifiable<K> {

    @Nonnull
    K getId();

}

A special test enum whose members are associated with a key:

public enum BinaryDigit implements IIdentifiable<Integer> {

    ZERO(0),
    ONE(1);

    private final Integer id;

    BinaryDigit(final Integer id) {
        this.id = id;
    }

    @Override public final Integer getId() {
        return id;
    }

}

An utility method that builds an IIdentifiable-enum index using Google Guava:

public static <K, E extends Enum<E> & IIdentifiable<K>> Map<K, E> enumIndexOf(final Class<E> type) {
    return uniqueIndex(asList(type.getEnumConstants()), e -> {
        return e.getId();
    });
}

Please note that the last method lambda can be simplified to a method reference like this:

public static <K, E extends Enum<E> & IIdentifiable<K>> Map<K, E> enumIndexOf(final Class<E> type) {
    return uniqueIndex(asList(type.getEnumConstants()), E::getId);
}

Once this refactoring is performed, the Retrolambda (I'm using the Maven plugin) is not able to backport the method reference producing the following error during the build:

Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Enum; not a subtype of implementation type interface halo.base.IIdentifiable
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
    at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
    at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:625)
    at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:647)
    at net.orfjackal.retrolambda.lambdas.LambdaReifier.callBootstrapMethod(LambdaReifier.java:110)
    at net.orfjackal.retrolambda.lambdas.LambdaReifier.reifyLambdaClass(LambdaReifier.java:37)
    ... 37 more

My JDK version is 1.8.0.40 (64). Could you please check? Thanks!


(Also it was difficult to find out which class fails. Is it possible to configure the Retrolambda Maven plugin to report which classes and methods fail to be backported? Currently the plugin only reports the previously saved lambdas like Saving lambda class: foo/bar/Baz$$Lambda$1, and I couldn't find the failed classes even with the Maven option -X set on.)

Thanks. I've located that the thing which triggers this bug is E extends Enum<E> & IIdentifiable<K>. The bytecode which creates the method reference thinks that the getId method is on the Enum class, when in reality it is on the IIdentifiable interface. I'll continue planning a fix for it.

@orfjackal thank you. One more question please: would it be possible to mention problematic classes like BinaryDigit in the error message as well for similar exceptions? It would be very and very nice to have a little more detailed message if possible.

Error reporting improved. Earlier it reported only problematic lambda classes. Now it reports all classes.

@orfjackal this is great, thank you! :)

And now it reports also the lambda/method reference which caused the problem. :)

The improved error messages is included in Retrolambda 2.1.0. The fix for this issue is still under work.