I obtain a remote reference from an RMI registry; lets call it s. Now, s is of (interface) type S which offers a method m(A, B, int).
On the client, I have implementations of A and B which both extend UnicastRemoteObject (and are therefore automatically exported). Consider instances a and b, respectively.
Now I call m(a, b, 0). It compiles, but fails at runtime with the very non-informative
java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
at $Proxy0.m(Unknown Source)
[... application specific sites]
Sadly, NativeMethodAccessorImpl.invoke0 is natively implemented and can not be inspected. So, I am at a total loss. Obviously, types match, otherwise the original code should not compile, right?
What can be reasons for this?
Edit: We use Java 6. The error can be reproduced on Ubuntu 11.04 32bit, Ubuntu 10.10 64bit and Windows 7 32bit.
Edit 2: I implemented some dummy methods on S to test individual parameters. Turns out, s.n(), s.t0(b) and s.t1(0) work as expected; only s.t2(a) fails. This implies that something is wrong with how I implemented A, doesn’t it?
The only striking difference between A and B (aside from actual content, of course) is that A is a class extending UnicastRemoteObject and follows the convention of a remote interface but does not implement a distinguished remote interface. B is a remote interface an implementation of which I pass.
Turns out the information provided in my second edit is crucial.
You can only export/use as remote objects instances of classes that explicitly implement an interface which extends
Remote. It is, in particular, not sufficient to have a class extendingUnicastRemoteObject—even though that one implementsRemote! In that case, everything compiles and exports just fine, but actually passing the object remotely causes the above exception.I suppose that creating skeletons/stubs for a remote type for which no remote interface exists somehow fails. There should be a better treatment for that, but well.
Edit: To clarify:
UnicastRemoteObjectimplementsRemote. Now, having something likeis not sufficient, even though
AimplementsRemoteindirectly. You will be able to instantiate (i.e. export), but not pass it remotely as anA.You need to do
Instances of
BImplcan be passed remotely asBas you would expect. So it appears that you need to implement a distinguished remote interface aside fromRemoteif you want to have proper remote objects.