Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interface field using lambda-style interface implementation causes VerifyError on Android < 5.0 #42

Closed
mgrzechocinski opened this issue Dec 30, 2014 · 3 comments

Comments

@mgrzechocinski
Copy link

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

@mgrzechocinski mgrzechocinski changed the title Default interface implementation causes VerifyError on Android < 5.0 Interface field using lambda-style interface implementation causes VerifyError on Android < 5.0 Dec 30, 2014
luontola added a commit that referenced this issue Jan 6, 2015
@luontola
Copy link
Owner

luontola commented Jan 6, 2015

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.

@luontola
Copy link
Owner

luontola commented Jan 6, 2015

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.

@mgrzechocinski
Copy link
Author

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 :)

aphexcx added a commit to GiveNow/givenow-android that referenced this issue Nov 14, 2015
…ods on an interface result in an unexpected opcode 00f8 message from dalvikvm on devices API <21.

Could be related to luontola/retrolambda#42
This means I can't use lambdas with animationEndListeners. Oh well.
(The brokenness of default methods on interfaces could also be the cause of the absurdities discovered in 98e0d2e).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants