Поскольку вы сказали, что «позор, API-интерфейс LambdaMetaFactory настолько сложен», следует отметить, что это можно сделать проще.
Во-первых, при использовании LambdaMetaFactory
используйте его прямо:
Lookup lookup = MethodHandles.lookup();
MethodType fType = MethodType.methodType(void.class, RoutingContext.class);
MethodHandle mh = lookup.findVirtual(HomeHandler.class, "handle", fType);
Handler<RoutingContext> lambda = (Handler<RoutingContext>) LambdaMetafactory.metafactory(
lookup, "handle", MethodType.methodType(Handler.class, HomeHandler.class),
fType.erase(), mh, fType).getTarget().invokeExact(new HomeHandler());
Вы собираетесь вызвать метод экземпляра с связанным получателем, а тип целевого метода, исключая получателя, идентичен параметру instantiatedMethodType
.Кроме того, поскольку предел T
в Handler<T>
равен Object
, вы можете просто использовать erase()
для этого типа метода, чтобы получить стертую подпись для параметра samMethodType
.
Это не всегдатак просто.Попробуйте связать метод static int method(int x)
с Consumer<Integer>
.Тогда параметр samMethodType
равен (Object)void
, параметр instantiatedMethodType
равен (Integer)void
, а сигнатура целевого метода - int(int)
.Вам нужны все эти параметры, чтобы правильно описать код для генерации.Учитывая, что другие (первые три) параметры обычно заполняются JVM в любом случае, этот метод уже требует только необходимый минимум.
Во-вторых, если вам не нужна максимальная производительность, вы можете просто использоватьреализация на основе Proxy
:
MethodHandle mh = MethodHandles.lookup().findVirtual(HomeHandler.class,
"handle", MethodType.methodType(void.class, RoutingContext.class));
Handler<RoutingContext> lambda = MethodHandleProxies.asInterfaceInstance(
Handler.class, mh.bindTo(new HomeHandler()));
Эта опция существует даже с Java 7