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.