Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expected to unbox a 'String' primitive type but was returned null

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:

  1. java.lang.reflect.Proxy.newProxyInstance() method returns null

  2. The following kinds of errors, depending on different versions I've tried of my code below:

    1. Expected to unbox a 'int' primitive type but was returned null

    2. 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?

like image 989
Michael Osofsky Avatar asked Feb 18 '26 16:02

Michael Osofsky


1 Answers

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.

like image 108
Michael Osofsky Avatar answered Feb 21 '26 04:02

Michael Osofsky