shilrast
shilrast

Reputation: 51

Methodhandle private method called using findVirtual

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");}
}

Upvotes: 5

Views: 2795

Answers (1)

Javasick
Javasick

Reputation: 3003

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");
        }
    }
}

Update for Java 11 +

Code with error

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 Inner().m();
        MethodHandle mh = MethodHandles.lookup()
            .findVirtual(Inner.class, "m", MethodType.methodType(void.class));
        mh.invoke(new Inner());
    }
}

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

Working version with reflection API

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

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

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

Upvotes: 3

Related Questions