4

Java doc of MethodHandle says that private method should invoke via findSpecial.But in the following example I am able to invoke it via findVirtual.

Could somebody please explain what am I missing here?

 import java.lang.invoke.MethodHandles;
import java.lang.invoke.*;

import java.lang.invoke.MethodType;

public class PrivateClassMethodLookupTest{
    public static void main(String[] args) throws Throwable{
     new PrivateClassMethodLookupTest().m();
     MethodHandle mh =   MethodHandles.lookup()
                .findVirtual(PrivateClassMethodLookupTest.class, "m", MethodType.methodType(void.class));
      mh.invoke(new PrivateClassMethodLookupTest());
    }

    private void m() { System.out.println("in m");}
}
shilrast
  • 41
  • 2

1 Answers1

2

You able to invoke it because you have access to private methods from the same class, where main is running Try run this code:

package com.company;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class PrivateClassMethodLookupTest {
    public static void main(String[] args) throws Throwable {
        new PrivateClassMethodLookupTest.Inner().m();
        MethodHandle mh = MethodHandles.lookup()
                .findVirtual(PrivateClassMethodLookupTest.Inner.class, "m", MethodType.methodType(void.class));
        mh.invoke(new PrivateClassMethodLookupTest.Inner());
    }

    static class Inner {
        private void m() {
            System.out.println("in m");
        }
    }
}

To call private methods you should use Reflection API and change method access type:

package com.company;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;

public class PrivateClassMethodLookupTest {
    public static void main(String[] args) throws Throwable {
        new PrivateClassMethodLookupTest.Inner().m();
        Method declaredMethod = PrivateClassMethodLookupTest.Inner.class.getDeclaredMethod("m");
        declaredMethod.setAccessible(true);
        MethodHandle mh = MethodHandles.lookup().unreflect(declaredMethod);
        mh.invoke(new PrivateClassMethodLookupTest.Inner());
    }

    static class Inner {
        private void m() {
            System.out.println("in m");
        }
    }
}
Javasick
  • 2,753
  • 1
  • 23
  • 35
  • Is there a way we can call Inner.m from PrivateClassMethodLookupTest? MethodHandles.lookup() .findSpecial(....) not working – nantitv Jan 13 '16 at 11:54
  • 1
    It's posible using reflection API Method declaredMethod = PrivateClassMethodLookupTest.Inner.class.getDeclaredMethod("m"); declaredMethod.setAccessible(true); MethodHandle mh = MethodHandles.lookup().unreflect(declaredMethod); mh.invoke(new PrivateClassMethodLookupTest.Inner()); – Javasick Jan 13 '16 at 12:58
  • Do u know why it's not possible with findSpecial? – nantitv Jan 13 '16 at 14:01
  • from [JavaDoc](https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandles.Lookup.html) `if the explicitly specified caller class is not identical with the lookup class, or if this lookup object does not have private access privileges, the access fails` – Javasick Jan 13 '16 at 14:19
  • 2
    @nantitv: It’s possible if `Inner` creates a `Lookup` object via `MethodHandles.lookup()` having the appropriate access permission and hands it over to the outer class. The lookup object encapsulates the access and whoever gets hands on it may use it to lookup (and eventually invoke) `private` methods of the associated class. – Holger Jan 18 '16 at 16:18