Passing a callback object results in a java.lang.IllegalArgumentException

In an application using JNBridgePro in a .NET-to-Java direction, you attempt to pass as an argument an object that has been annotated as a [Callback] or [AsyncCallback]. Doing so results in a java.lang.IllegalArgumentException being thrown.

This exception is caused when your callback object also inherits from a proxied Java class in addition to a proxied interface. In addition, the proxied method that you are calling expects an argument of the proxied class rather than the interface.

Assume you have the following Java classes:

public interface I
{
void m();
}

public class C implements I
{
public void m() {}
}

public class D
{
public static void f(C c) {}
}

Generate proxies for I, C, and D.

Now, write the following C# code:

[Callback(“I”)]
public class C2 : C, I
{
public override void m() {}
}

Compile that, along with the following code:

D.f(new C2());

Executing the above call will cause a java.lang.IllegalArgumentException to be thrown.

The reason for this is that when a callback-annotated object is passed back to the Java side, the resulting object that is received on the Java side is of a special internal and anonymous class that implements the interface I (the knowledge of which is passed through to the Java side by way of the [Callback] attribute), but which does not inherit from C (unlike the original .NET object). Thus, when an attempt is made to pass it to the Java method f(), which expects an object of type C, the IllegalArgumentException is thrown. If D.f() were written as:

public static void f(I i) {}

there would be no exception thrown. However, if the method attempted to cast the argument i to class C:

public static void f(I i) { C c = (C) i; }

a ClassCastException will be thrown because the actual object passed does not inherit from class C.

To avoid the problem, only pass callback-annotated objects to methods that expect arguments of an interface type included among the [Callback] or [AsyncCallback] annotations, and also make sure not to have any code in the message body or elsewhere that attempts to casts the interface-typed value to a specific non-interface Java class.