InvokeExact en el objeto, cuyo tipo es cargado dinámicamente por el cargador de clases
He pasado todo el día en este problema. Mi problema es cómo hacer una invocación MethodHandle.invokeExact en una instancia, cuyo tipo de clase se carga dinámicamente en el tiempo de ejecución del programa. Para aclarar el problema, muestro mi código de muestra a continuación:
Class<?> expClass = new MyClassLoader().load(....)
//expClass is AddSample.class which is subclass of BaseTemplate
BaseTemplate obj = expClass.getConstructor(...)
.newInstance(...);
MethodHandle myMH = MethodHandles.lookup().findVirtual(expClass, methodName,..);
System.out.println("Object type "+obj.getClass()); //Print AddSample
// If obj is declared as "AddSample obj", the runtime would be OK.
assertEquals((int)myMH.invokeExact(obj,"addintaasdsa" , 10 , 20.0f), 12);
En esta muestra, expClass se carga dinámicamente y su tipo de clase esAddSample
. La instancia de obj en la siguiente línea se declara como BaseTemplate, y su tipo real esAddSample
. La clase AddSample es una subclase de BaseTemplate. Luego, se crea un MethodHandle myMh para la función add deAddSample
pero la invocación de myMH falla debido a que receptorType no coincide.
losmyMH.invokeExact
plantea error de tiempo de ejecución
java.lang.invoke.WrongMethodTypeException: expected (AddSample,String,int,float)int but found (Object,String,int,float)int
porque el receptor de estomyMH
se declara en expClass (AddSample), pero el receptorobj
la corriente proporcionada se declara BaseTemaplte, aunque la clase del obj es AddSample. InvokeExact requiere coincidencia exacta de parámetros.
Mi problema podría simplificarse como: ¿cómo convertir una instancia de su tipo base a un tipo hijo que se carga dinámicamente?
BaseTemplate obj = ...
Class<?> newType = Class('AddSample') //dynamic loaded...
cambia el tipo declarado de obj a AddSample que se carga dinámicamente ...?UPDATE:
Class<T> expClass = (Class<T>) new MyClassLoader().run(className, methodName, b);
BaseTemplate obj = ..
Class<T> newType = (Class<T>) obj.getClass().getClassLoader().loadClass("AddSample");
T tObj = newType.cast(obj);
assertEquals((int)myMH.invokeExact(tObj,"addintaasdsa" , 10 , 20.0f), 12);
El uso de cast no ayuda a solucionar el problema, que es el mismo resultado anterior. La razón sigue siendo que el parámetro dado no coincide exactamente con la declaración myMH. Sería más claro cuando verifico los bytecodes generados:
L23 # For cast
LINENUMBER 126 L23
ALOAD 10: newType
ALOAD 8: obj
INVOKEVIRTUAL Class.cast (Object) : Object #tObj is Object and its real type is AddSample here
ASTORE 11
L24
LINENUMBER 128 L24
ALOAD 9: myMH # Push myMH to stack
ALOAD 11: tObj # Push tObj to Stack. tObj is declared Object type and its real type is AddSample.
LDC "addintaasdsa" #Push String to Stack
BIPUSH 10 #Push int to Stacl
LDC 20.0 #Push float to Stack
INVOKEVIRTUAL MethodHandle.invokeExact (Object, String, int, float) : int
el myMH apunta a(AddSample,String,int,float)int
, pero los parámetros dados:(Object, String, int, float)
, y esto da como resultado un error de tiempo de ejecución que se me mostró anteriormente.
Gracias