I want to try and avoid reflection for invoking a constructor and am trying to follow the LamdaMetaFactory approach taken in this post - Faster alternatives to Java's reflection
My class that I want to construct looks like:
interface DBBroker {}
public class NativeBroker implements DBBroker {
public NativeBroker(BrokerPool brokerPool, final Configuration configuration) {
}
}
Using LambaMetaFactory
I am trying to construct a BiFunction<BrokerPool, Configuration, DBBroker>
to replace a direct call to the constructor.
My code so far looks like:
Class<? extends DBBroker> clazz =
(Class<? extends DBBroker>) Class.forName("org.exist.storage.NativeBroker");
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh =
lookup.findConstructor(clazz, MethodType.methodType(void.class, new Class[] {BrokerPool.class, Configuration.class}));
BiFunction<BrokerPool, Configuration, DBBroker> constructor
(BiFunction<BrokerPool, Configuration, DBBroker>)
LambdaMetafactory.metafactory(
lookup, "apply", MethodType.methodType(BiFunction.class),
mh.type(), mh, mh.type()).getTarget().invokeExact();
final DBBroker broker = constructor.apply(database, conf);
Unfortunately this returns the error -
AbstractMethodError: Method org/exist/storage/BrokerFactory$$Lambda$55.apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; is abstract.
I have tried modifying the various types passed to LambdaMetafactory.metafactory
but I can't quite seem to get this right, and the Javadoc is certainly not easily understood.
Can someone advise please?
The mistake you made is in the SAM type you used. The erased type of the apply
method has to be used for that, so that would be
methodType(Object.class, Object.class, Object.class)
But you could also use mh.type().generic()
which returns the same thing:
BiFunction<BrokerPool, Configuration, DBBroker> constructor =
(BiFunction<BrokerPool, Configuration, DBBroker>)
LambdaMetafactory.metafactory(
lookup, "apply", methodType(BiFunction.class),
mh.type().generic(), mh, mh.type()).getTarget().invokeExact();
// ^^^^^^^^^^^^^^^^^^^