Interface field using lambda-style interface implementation causes VerifyError on Android < 5.0
mgrzechocinski opened this issue · comments
Hi,
I've been using retrolambda for over 3 months with success but recently found an issue. To convince myself that issue is not related to my project-specific configuration I created sample project with latest version of retrolambda gradle plugin v2.5.0
. You can simply try to run it to reproduce the issue.
Thinking it's rather retrolambda than plugin issue, I'm addressing it to this github project.
Steps to reproduce
- Create an interface and it's empty implementation as it's static field. Assign activity field to this default implementation (source code available here)
public class MainActivity extends ActionBarActivity {
public interface OnProgressChangeListener {
OnProgressChangeListener NULL = progress -> { };
public void onProgressChanged(int progress);
}
OnProgressChangeListener onProgressChangeListener = OnProgressChangeListener.NULL;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
- Run this Activity
- Results:
- Android 5 - works fine
- Android 4.4 and below - crash:
12-30 22:24:19.412 1773-1773/retrolambda_example W/dalvikvm﹕ DexOpt: method is in an interface
12-30 22:24:19.412 1773-1773/retrolambda_example I/dalvikvm﹕ Could not find method retrolambda_example.MainActivity$OnProgressChangeListener.lambda$static$0, referenced from method retrolambda_example.MainActivity$OnProgressChangeListener.access$lambda$0
12-30 22:24:19.412 1773-1773/retrolambda_example W/dalvikvm﹕ VFY: unable to resolve static method 12260: Lnet/grzechocinski/android/retrolambda_example/MainActivity$OnProgressChangeListener;.lambda$static$0 (I)V
12-30 22:24:19.412 1773-1773/retrolambda_example W/dalvikvm﹕ VFY: rejecting opcode 0x71 at 0x0002
12-30 22:24:19.412 1773-1773/retrolambda_example W/dalvikvm﹕ VFY: rejected Lnet/grzechocinski/android/retrolambda_example/MainActivity$OnProgressChangeListener;.access$lambda$0 (I)V
12-30 22:24:19.412 1773-1773/retrolambda_example W/dalvikvm﹕ Verifier rejected class Lnet/grzechocinski/android/retrolambda_example/MainActivity$OnProgressChangeListener;
12-30 22:24:19.412 1773-1773/retrolambda_example D/AndroidRuntime﹕ Shutting down VM
12-30 22:24:19.412 1773-1773/retrolambda_example W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0xa4d36b20)
12-30 22:24:19.412 1773-1773/retrolambda_example E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: retrolambda_example, PID: 1773
java.lang.VerifyError: net/grzechocinski/android/retrolambda_example/MainActivity$OnProgressChangeListener
at retrolambda_example.MainActivity.<init>(MainActivity.java:15)
at java.lang.Class.newInstanceImpl(Native Method)
at java.lang.Class.newInstance(Class.java:1208)
at android.app.Instrumentation.newActivity(Instrumentation.java:1061)
When I change to anonymous class version:
public interface OnProgressChangeListener {
OnProgressChangeListener NULL = new OnProgressChangeListener() {
@Override
public void onProgressChanged(int progress) {
}
};
public void onProgressChanged(int progress);
}
everything works fine on every version of Android platform.
I'm building by gradle & jvm 8:
↪ g --version
------------------------------------------------------------
Gradle 2.1
------------------------------------------------------------
Build time: 2014-09-08 10:40:39 UTC
Build number: none
Revision: e6cf70745ac11fa943e19294d19a2c527a669a53
Groovy: 2.3.6
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_05 (Oracle Corporation 25.5-b02)
OS: Mac OS X 10.10.2 x86_64
It is somehow related to ART introduced in Android 5.0? Any plans to fix that? Maybe it's worh mentioning in README as a known limitation?
Thanks in advance for any response
Thanks. I missed testing that corner case. Fixing it will be a bit harder than usual, but I'll try to do it soon. In the meanwhile the workaround is to not use lambdas inside interfaces.
I was able to reuse the experimental support for default methods and static methods on interfaces, so fixing this went faster than expected. 😄 This is now fixed in Retrolambda 1.8.1
I don't understand why it anyways did work on Android 5 before this fix. The generated bytecode should not have worked on any Java versions, because only Java 8 added support for static methods in interfaces. 😦 You better test the new Retrolambda version on Android.
Thanks for your support and the new release. I've just updated my sample project by specifying retrolambda.jar dependency to the latest v1.8.1:
Now it works on Android 2.3, 4.3, 4.4 and 5 as well. Considered as fixed. Thank you once again :)