For backward compatability testing, i'm creating my own class loader to load some of my code from previous version. After I have my custom object (from the custom class older), i'm invoking the API of it using reflection. However, when such API method have custom argument (isn't part of java library), for example:
public void MyMethod(MyObj a) {}
When i'm invoking this method using reflection i'm getting:
java.lang.IllegalArgumentException: argument type mismatch
Because i'm passing MyObj from the default class loader while the method expect to get MyObj from the custom class loader.
The code I'm using to invoke the method (while agent was loded by my custom classloader and the arguments to agent's api methods arrived from my test class which loded by the default class loader)
private Object invoke(Object... args) {
try {
final String methodName = getMethodName();
final Class<?>[] methodArgs = getMethodArgs(methodName);
return agent.getClass().getMethod(methodName, methodArgs).invoke(agent, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
private Class<?>[] getMethodArgs(String methodName) {
final Method[] declaredMethods = agent.getClass().getDeclaredMethods();
for (Method method : declaredMethods) {
if (method.getName().equals(methodName)) {
return method.getParameterTypes();
}
}
return new Class<?>[0];
}
private String getMethodName() {
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[3];
return e.getMethodName();
}
How can I workaround this issue? (I can't pass common interface to the method because myCustomObject does not implement interface that exist in a shared module, and i can't add one now because the old jars won't know it)
You can use your custom class loader to load a class "DefaultCtorMyObjWrapper" that extends MyObj (loaded by the custom class loader). DefaultCtorMyObjWrapper wraps an instance of "MyObj" that was loaded by the default constructor (the refrence should be kept as an Object). DefaultCtorMyObjWrapper overrides all of MyObj's methods and delegates invocations using reflection to the wrapped MyObj.
Should look somthing like this:
class DefaultCtorMyObjWrapper{
Object _defaultCtorMyObj;
public DefaultCtorMyObjWrapper(Object defaultCtorMyObj){
_defaultCtorMyObj = defaultCtorMyObj;
}
public method1(){
// invoke method1 on _defaultCtorMyObj using reflcetion
}
}
If MyObj's methods recieve objects as parameters you might need some more tweaking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With