使用远程参数的 Java RMI 调用失败
我从 RMI 注册表获取远程引用;我们称之为s
。现在,s
是(接口)类型 S
,它提供了方法 m(A, B, int)
。
在客户端上,我有 A
和 B
的实现,它们都扩展了 UnicastRemoteObject
(因此会自动导出)。分别考虑实例 a
和 b
。
现在我调用m(a, b, 0)
。它可以编译,但在运行时失败,并显示非常无信息的内容。
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]
遗憾的是,NativeMethodAccessorImpl.invoke0
是本机实现的,无法检查。所以,我完全不知所措。显然,类型匹配,否则原始代码不应该编译,对吧?
造成这种情况的原因是什么?
编辑:我们使用 Java 6。该错误可以在 Ubuntu 11.04 32 位、Ubuntu 10.10 64 位和 Windows 7 32 位上重现。
编辑2:我在S上实现了一些虚拟方法来测试各个参数。事实证明,sn()
、s.t0(b)
和 s.t1(0)
按预期工作;只有 s.t2(a)
失败。这意味着我实现 A
的方式有问题,不是吗?
A
和 B
之间唯一显着的区别(当然,除了实际内容)是 A
是一个扩展 UnicastRemoteObject< 的类。 /code> 并遵循远程接口的约定,但不实现显着的远程接口。
B
是一个远程接口,我传递了它的实现。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
事实证明,我第二次编辑中提供的信息至关重要。
您只能导出/使用显式实现扩展
Remote
接口的类的远程对象实例。特别是,拥有一个扩展UnicastRemoteObject
的类是不够的——即使该类实现了Remote
!在这种情况下,一切都可以正常编译和导出,但实际上远程传递对象会导致上述异常。我认为为不存在远程接口的远程类型创建骨架/存根会以某种方式失败。应该有更好的治疗方法,但是很好。
编辑:澄清一下:
UnicastRemoteObject
实现了Remote
。现在,即使
A
间接实现了Remote
,拥有类似的东西还不够。您将能够实例化(即导出),但不能将其作为A
远程传递。您需要
按照您的预期将
BImpl
的实例作为B
远程传递。因此,如果您想拥有适当的远程对象,那么除了Remote
之外,您还需要实现一个独特的远程接口。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:
UnicastRemoteObject
implementsRemote
. Now, having something likeis not sufficient, even though
A
implementsRemote
indirectly. You will be able to instantiate (i.e. export), but not pass it remotely as anA
.You need to do
Instances of
BImpl
can be passed remotely asB
as you would expect. So it appears that you need to implement a distinguished remote interface aside fromRemote
if you want to have proper remote objects.