如何找到Java8方法引用的目标?

我想捕获对模拟对象的调用

public interface Service { public String stringify(Object o); } service = mockery.mock(Service.class); mockery.allowing(service::stringify).with(42).will(() -> "42"); 

所以内部allowing我有一个Function

是否有任何reflecto-magic可以让我从方法参考创建的函数中找到服务?

 public WithClause allowing(Function f) { Object myServiceBackAgain = findTargetOf(function); .... } 

我知道函数将始终来自这些方法引用,所以我很乐意尽可能地向下转换。

这与相关的问题不同是否可以将方法引用转换为MethodHandle? 因为,一开始它不是同一个问题,只是在相关领域。 即使我可以获得MethodHandle,我也无法从中获取目标。

使用此SOpost中的技巧,您可以找到目标。 下面的重要方法是findTarget 。 事实certificate,lambdas确实捕获了它们的目标,你可以从SerializedLambda访问它们。

然而,这是一个非常讨厌的反思黑客,它可能在未来的版本中打破。 我不宽恕它的用法。

 import java.io.Serializable; import java.lang.invoke.SerializedLambda; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Optional; import java.util.function.Function; public class FindMethodReferenceTarget { public static void main(String[] args) { String s = "123"; Optional target = findTarget(s::charAt); System.out.println(target.get().equals(s)); Object o = new FindMethodReferenceTarget(); target = findTarget(o::equals); System.out.println(target.get().equals(o)); } private static  Optional findTarget( DebuggableFunction methodReference) { return getLambda(methodReference).map(l -> l.getCapturedArg(0)); } private static Optional getLambda(Serializable lambda) { for (Class cl = lambda.getClass(); cl != null; cl = cl.getSuperclass()) { try { Method m = cl.getDeclaredMethod("writeReplace"); m.setAccessible(true); Object replacement = m.invoke(lambda); if (!(replacement instanceof SerializedLambda)) { break; // custom interface implementation } SerializedLambda l = (SerializedLambda) replacement; return Optional.of(l); } catch (NoSuchMethodException e) { // do nothing } catch (IllegalAccessException | InvocationTargetException e) { break; } } return Optional.empty(); } @FunctionalInterface private static interface DebuggableFunction extends Serializable, Function {} } 

找不到目标是没有直接的方法,因为方法引用只是被转换为lambdas(根据定义,匿名)。 所以你需要使用一种解决方法。

大概你熟悉Java 7的代理,因为你已经设法实现了你的mock工厂方法。

然后解决方法是,当有人调用您的allowing方法时,您设置某种全局标志以警告您要记录下一个调用的所有模拟,然后调用您给出的lambda。 通过查看哪个模拟记录了调用,您现在已经找到了方法引用的目标,并且您可以取消设置全局标志并继续使用其余的模拟框架。

我知道,这很难看。