Skip to content

Method references to private methods #17

Closed

Description

@naixx

Hi. The problem is:

{
  someObserable.finallyDo(this::myProblemMethod);
}

private void myProblemMethod(){}

The code is compiled and dexed to run on Davlik VM. But in runtime on an android device I get warnings and the method isn't called, of course.

 DexOpt: illegal method access (ca;.myProblemMethod ()V from (Fragment$$Lambda$1;)
 I/dalvikvm﹕ Could not find method myProblemMethod, referenced from method Fragment$$Lambda$1.call
VFY: unable to resolve virtual method 43525:

The code works as a lambda if myProblemMethod is package private, public, everything except private. The method can be called explicitly. But it doesn't work as a method reference. Warnings appear only once.

So, is it a problem, that retrolambda somehow processes references, so that dex excludes them from the build?

Activity

  1. added a commit that references this issue on May 13, 2014
  2. luontola commented on May 13, 2014

    @luontola
    Owner

    Thanks. I was able to reproduce it. I'll have a look at solving it soon, maybe tomorrow.

    I'm guessing that this has something to do with how in Java 8 the lambda classes have some special handling to that they can call private methods of other classes. Retrolamdba should probably detect when a method reference targets a private method and make it package private.

  3. changed the title [-]Davlik optimisation of method references[/-] [+]Method references to private methods[/+] on May 13, 2014
  4. luontola commented on May 13, 2014

    @luontola
    Owner

    This isn't a Dalvik specific problem, so I renamed the issue.

  5. naixx commented on May 13, 2014

    @naixx
    Author

    Great to hear, that the problem is identified!

  6. luontola commented on May 14, 2014

    @luontola
    Owner

    Still one bug remains (seems to depend on JDK 8 build). Working on it...

  7. luontola commented on May 14, 2014

    @luontola
    Owner

    The fix is included in Retrolambda 1.2.2. It should show up in Maven Central in a couple of hours.

  8. naixx commented on May 14, 2014

    @naixx
    Author

    Looks like magic, thanks!

  9. naixx commented on May 16, 2014

    @naixx
    Author

    Hello, @orfjackal !

    After updating to the new version, I've catched a crash.

     @Test
        public void call_of_method_with_reference(){
            class InnerClass {
                void foo(){
                    Runnable r = LambdaTest.this::privateVoidMethod;
                    r.run();
                }
            }
            new InnerClass().foo();
            privateVoidMethod();
            assertThat(privateInstanceMethod(), is("foo"));
        }

    The code structure is like this. I haven't checked it in a test.

  10. luontola commented on May 18, 2014

    @luontola
    Owner

    Please submit a SSCCE. You example doesn't compile and I haven't managed to reproduce the problem.

  11. naixx commented on May 18, 2014

    @naixx
    Author

    @orfjackal ok, finally I managed to reproduce the problem.

    void thisMethodIsAlsoReferenced() {
        Observable.from("foo").lift((Operator<String, String>) (subscriber) -> {
            Runnable ref = MyOuterClass.this::problemPrivateMethod; //we make a reference in an anonymous class
            ref.run();
            return subscriber;
        }).subscribe(s -> {
            L.e(s);
        });
        problemPrivateMethod(); //java.lang.NoSuchMethodError
    }

    Unfortunately, I can't reproduce the problem in tests.

  12. luontola commented on May 18, 2014

    @luontola
    Owner

    Please make that example short and self contained (http://www.sscce.org/) so that I can run it. Or send the me .class files before and after processing that code with Retrolambda.

    Does the problem happen with Oracle JVM or only Dalvik VM?

  13. naixx commented on May 18, 2014

    @naixx
    Author

    I tried to make a simple junit test in a fork of your repo, but the problem didn't appear in that case.
    The only way to reproduce is run on Android device.

    https://github.com/naixx/PrivateMethodAndroidBug
    Here is an Android project, that reproduces the problem with Davlik VM. I hope it matches SSCCE a bit :)

    The warnings I get:

    I/dalvikvm﹕ Could not find method com.example.testbug.app.MainActivity.problemPrivateMethod, referenced from method com.example.testbug.app.MainActivity.methodCall
    W/dalvikvm﹕ VFY: unable to resolve direct method 8443: Lcom/example/testbug/app/MainActivity;.problemPrivateMethod ()V
    

    And error on method usage.

    I've also added classes before and after retrolambda from a real project. The problem method is cleanup and problemPrivateMethod

  14. luontola commented on May 18, 2014

    @luontola
    Owner

    How to run that project? I can compile it with gradlew clean build but I haven't done any Android development and I can't figure out the command for starting the application.

  15. naixx commented on May 18, 2014

    @naixx
    Author

    If you don't have device, the easiest way is to run it through emulator or Genymotion. After build to run it on device or emulator type adb install ResultedFile.apk.
    You can also try Android Studio for that propose. It is the simplest way.
    I hope, this can help.

  16. luontola commented on May 18, 2014

    @luontola
    Owner

    Thanks. I was able to reproduce it. Let's continue discussion in #18

  17. added a commit that references this issue on Aug 11, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions