java - How can I find the target of a Java8 method reference? -
i want capture calls mock object
public interface service { public string stringify(object o); } service = mockery.mock(service.class); mockery.allowing(service::stringify).with(42).will(() -> "42");
so inside allowing
have function<object, string>
is there reflecto-magic let me find service function created method reference?
public withclause allowing(function<t,r> f) { object myservicebackagain = findtargetof(function); .... }
i know function come these method references, i'm happy down-cast as necessary.
this not same question related is possible convert method reference methodhandle? because, start isn't same question, in related area. , if can methodhandle, can't target it.
using trick this post can find target. important method below findtarget
. turns out, lambdas indeed capture targets, , can access them serializedlambda
.
however, pretty nasty reflection hack , it's break in future versions. not condone usage.
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<object> 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 <t, r> optional<object> findtarget( debuggablefunction<t, r> methodreference) { return getlambda(methodreference).map(l -> l.getcapturedarg(0)); } private static optional<serializedlambda> getlambda(serializable lambda) { (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) { // nothing } catch (illegalaccessexception | invocationtargetexception e) { break; } } return optional.empty(); } @functionalinterface private static interface debuggablefunction<t, r> extends serializable, function<t, r> {} }
Comments
Post a Comment