I am trying to use Java Reflection to call a method which takes a callback as an argument. I instantiate all of the objects with Java Reflection. Also, I am using a Java Dynamic Proxy Class as the callback argument.
I'm a couple of strange behaviors:
java.lang.reflect.Proxy.newProxyInstance() method returns null
The following kinds of errors, depending on different versions I've tried of my code below:
Expected to unbox a 'int' primitive type but was returned null
Expected to unbox a 'String' primitive type but was returned null
Here is the interface I want to instantiate as an anonymous object as a Java Dynamic Proxy Class:
public interface MyListener {
void onEvent(String eventName);
}
And here is how I instantiate the interface via newProxyInstance():
Object callbackObject = null;
try {
Class callbackClass = Class.forName("com.example.MyListener");
Class[] interfaceArray = new Class[]{callbackClass};
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("onMyEvent")) {
Log.d(TAG, "InvocationHandler.invoke onMyEvent");
}
return null;
}
};
callbackObject = java.lang.reflect.Proxy.newProxyInstance(
this.getClass().getClassLoader(),
interfaceArray,
invocationHandler);
}
catch (Throwable t) {
Log.e(TAG, "newProxyInstance got exception [" + t + "] caused by [" + t.getCause() + "]");
}
Log.d(TAG, "callbackObject=[" + callbackObject + "]");
if (null == callbackObject) {
Log.e(TAG, "callbackObject is null according to null check");
}
else {
Log.d(TAG, "callbackObject is NOT null according to null check");
}
The log messages seem to conflict about whether callbackObject is null:
callbackObject=[null]
callbackObject is NOT null according to null check
According to Why does newInstance() return null? it's not possible for newProxyInstance() to return null because it gets the value from newInstance().
So how can the result of newProxyInstance() be null and not null? And what do these error messages like Expected to unbox a 'int' primitive type but was returned null mean?
Solution: java.lang.reflect.Proxy.newProxyInstance() method returns null
I figured out the Object returned by newProxyInstance() is not null, it merely appears to be null. The log message that prints out the return value says it's null because Java implicitly calls toString() on the object. But since the object is a Proxy, it gets forwarded to my InvocationHandler. The real problem is with my InvocationHandler which always returns null. I thought null was suitable because the onEvent() method returns void. However, I didn't anticipate that toString() would also be forwarded to the InvocationHandler.
Solution: Expected to unbox a 'int' primitive type but was returned null
While trying to debug the apparent null, I ended up trying to call other methods on the object returned by newProxyInstance(), for example hashcode() and getClass(). All of these methods get forwarded to the InvocationHandler which wasn't expecting them and so it just returned null for everything. Since null is not a valid int, the hashcode() function resulted in the error Expected to unbox a 'int' primitive type but was returned null.
I was able to eliminate this error by making my InvocationHandler a little more robust:
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("onMyEvent")) {
Log.d(TAG, "InvocationHandler.invoke onMyEvent");
return null;
}
else if (String.class == method.getReturnType()) {
return "";
}
else if (Integer.class == method.getReturnType()) {
return Integer.valueOf(0);
}
else if (int.class == method.getReturnType()) {
return 0;
}
else if (Boolean.class == method.getReturnType()) {
return Boolean.FALSE;
}
else if (boolean.class == method.getReturnType()) {
return false;
}
else {
return null;
}
}
};
However, the actual solution for me was just to remove the debugging code that called hashcode(), etc. and trust that the newProxyInstance() result was not null. And in the future, keep in mind that the InvocationHandler gets forwarded all method calls.
Thanks to artaxerxe's solution for Proxy object throws NullPointerException for giving me the insight.
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