Last active
January 1, 2018 21:10
-
-
Save wreulicke/5d5e84763a63d52132516dd8eddca64d to your computer and use it in GitHub Desktop.
Get method name from method reference
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.github.wreulicke; | |
import static org.junit.Assert.assertTrue; | |
import java.lang.reflect.AccessibleObject; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Member; | |
import java.lang.reflect.Method; | |
import java.security.AccessController; | |
import java.security.PrivilegedExceptionAction; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import org.junit.Test; | |
import sun.misc.Unsafe; | |
public class GetMethodNameTest { | |
private static Method GET_CONSTANT_POOL; | |
private static Method GET_CONSTANT_POOL_SIZE; | |
private static Method GET_CONSTANT_POOL_METHOD_AT; | |
private static Unsafe UNSAFE; | |
static { | |
double JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version", "0")); | |
try { | |
UNSAFE = AccessController.doPrivileged(new PrivilegedExceptionAction<Unsafe>() { | |
@Override | |
public Unsafe run() throws Exception { | |
final Field f = Unsafe.class.getDeclaredField("theUnsafe"); | |
f.setAccessible(true); | |
return (Unsafe) f.get(null); | |
} | |
}); | |
GET_CONSTANT_POOL = Class.class.getDeclaredMethod("getConstantPool"); | |
String constantPoolName = | |
JAVA_VERSION < 9 ? "sun.reflect.ConstantPool" : "jdk.internal.reflect.ConstantPool"; | |
Class<?> constantPoolClass = Class.forName(constantPoolName); | |
GET_CONSTANT_POOL_SIZE = constantPoolClass.getDeclaredMethod("getSize"); | |
GET_CONSTANT_POOL_METHOD_AT = constantPoolClass.getDeclaredMethod("getMethodAt", int.class); | |
Field overrideField = AccessibleObject.class.getDeclaredField("override"); | |
long overrideFieldOffset = UNSAFE.objectFieldOffset(overrideField); | |
UNSAFE.putBoolean(GET_CONSTANT_POOL, overrideFieldOffset, true); | |
UNSAFE.putBoolean(GET_CONSTANT_POOL_SIZE, overrideFieldOffset, true); | |
UNSAFE.putBoolean(GET_CONSTANT_POOL_METHOD_AT, overrideFieldOffset, true); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
// thanks to https://github.com/jhalterman/typetools | |
@Test | |
public void test() throws Exception { | |
Consumer<String> lambda1 = System.out::println; | |
Function<String, String> lambda2 = String::new; | |
assertTrue("println".equals(getMethodName(lambda1))); | |
assertTrue("new".equals(getMethodName(lambda2))); | |
} | |
private static String getMethodName(Object methodRef) throws Exception { | |
Class<?> type = methodRef.getClass(); | |
Object constant = GET_CONSTANT_POOL.invoke(type); | |
for (int i = 0; i < getConstantPoolSize(constant); i++) { | |
Member member = getConstantPoolMethodAt(constant, i); | |
if (member == null | |
|| (member.getDeclaringClass().getName().equals("java.lang.invoke.SerializedLambda")) // ignore SerializedLambda | |
|| member.getDeclaringClass().isAssignableFrom(type)) | |
continue; | |
if (member instanceof Constructor) { | |
return "new"; | |
} | |
if (member instanceof Method) { | |
return member.getName(); | |
} | |
} | |
return null; | |
} | |
private static int getConstantPoolSize(Object constantPool) { | |
try { | |
return (Integer) GET_CONSTANT_POOL_SIZE.invoke(constantPool); | |
} catch (Exception ignore) { | |
return 0; | |
} | |
} | |
private static Member getConstantPoolMethodAt(Object constantPool, int i) { | |
try { | |
return (Member) GET_CONSTANT_POOL_METHOD_AT.invoke(constantPool, i); | |
} catch (Exception ignore) { | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment