¿Es posible obtener una referencia o método objeto de la función de un objeto mediante la reflexión?

user9613668:

Hay una clase.

class A {
    Mono<Response> testMap(Mono<Request> reqMono)
}

No es la interfaz funcional

interface MapHandler {
    Mono<?> handle(Mono<?> reqMono)
}

Ahora puedo escribir esto

{
A a = new A();
MapHandler handler = a::testMap;
}

Y quiero construir una herramienta que puede detectar todos los MapHandler en un frijol (objeto) y recogerlos.

He intentado esto.

List<MapHandler> list = initedList;
Method method = bean.getClass().getDeclaredMethods()[0];
list.put("methodName", req -> {
    return (Mono<?>) method.invoke(bean, req);
})

¿Es posible hacerlo por MethodHandleo LambdaMetaFactory?

HTNW:

Un esbozo de una solución que utiliza de forma explícita LambdaMetafactoryen la forma en que parece que quieren es:

// the signature of the method returned by LambdaMetaFactory
// it takes an object of bean's type and makes a MapHandler that calls one
// of its instance methods
MethodType mkLambdaType = MethodType.methodType(MapHandler.class, bean.getClass());
// the signature of the method in MapHandler being implemented
MethodType handleType = MethodType.methodType(Mono.class, Mono.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();

// FYI this won't search in supertypes
// getMethods() will, but you only get public ones even if you have more privileged access
// you decide what to do here; the loop body is the important thing
for(Method method : bean.getClass().getDeclaredMethods()) {
    if(Modifier.isStatic(method.getModifiers())) continue;
    try {
        MethodHandle target = lookup.unreflect(method);
        CallSite mkLambda = LambdaMetafactory.metafactory
            (lookup, "handle", mkLambdaType, handleType, target, handleType);
        list.add((MapHandler)mkLambda.getTarget().invoke(bean));
    } catch(IllegalAccessException | LambdaConversionException e) {
        // because I am lazy, I'm not checking that method has the correct type
        // I'm letting LambdaMetafactory throw if that's not the case
        // if you choose not to use LambdaMetafactory, you may have to implement
        // this type-checking
        continue;
    } catch(Throwable t) {
        // Throwables come from the MethodHandle#invoke call
        // but nothing should be thrown at all, because LambdaMetafactory
        // produces its errors from metafactory, early, which are caught above
        throw new RuntimeException("Unexpected error during reflection", t);
    }
}

Creo que esto es un gran desperdicio. Una aplicación común de la LambdaMetafactoryvoluntad probable crear una clase completamente nueva en la metafactoryllamada, devolviendo un CallSiteapuntador a un constructor o similar. Esto significa que cada MapHandlerque se obtiene es su propia clase anónima, creada en tiempo de ejecución. Por el contrario, su idea original de utilizar un lambda para invocar una Methodes mucho más agradable a la JVM. La lambda provoca la creación de una sola LambdaMetafactoryclase, que sostiene methody beancomo variables de instancia. Después de la primera carrera a través del código, en el que invokedynamicse bootstrap, cada uno MapHandlerse crea simplemente creando una instancia de esta clase anónima. Mi LambdaMetafactoryúnica solución parece aceptable si sólo se necesita relativamente pocos MapHandlers, pero cada uno se llama tan a menudo que la sobrecarga deMethod#invoke es muy alto.


Así que he ido por delante y hecho un poco de la evaluación comparativa rápida. En el caso de uso, donde inicializar MapHandlers al inicio del programa y luego sólo invocarlos, mi técnica y los suyos son aproximadamente los mismos. Ambos son tan rápido que no puedo medir realmente la diferencia en el tiempo necesario para llamar a los diferentes tipos de MapHandler. En general, LambdaMetafactoryes peor, porque la creación de la clase anónima lleva mucho tiempo. De hecho, los más clases que realice, más tiempo tomará. Mientras tanto, el method.invokelambda simplemente tiene que construir un objeto, que a menudo es miles de veces más rápido.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=214408&siteId=1
Recomendado
Clasificación