使用远程参数的 Java RMI 调用失败

发布于 2024-12-05 11:17:17 字数 2505 浏览 0 评论 0原文

我从 RMI 注册表获取远程引用;我们称之为s。现在,s 是(接口)类型 S,它提供了方法 m(A, B, int)

在客户端上,我有 AB 的实现,它们都扩展了 UnicastRemoteObject (因此会自动导出)。分别考虑实例 ab

现在我调用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 的方式有问题,不是吗?

AB 之间唯一显着的区别(当然,除了实际内容)是 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最丧也最甜 2024-12-12 11:17:17

事实证明,我第二次编辑中提供的信息至关重要。

您只能导出/使用显式实现扩展 Remote 接口的类的远程对象实例。特别是,拥有一个扩展 UnicastRemoteObject 的类是不够的——即使该类实现了 Remote!在这种情况下,一切都可以正常编译和导出,但实际上远程传递对象会导致上述异常。

我认为为不存在远程接口的远程类型创建骨架/存根会以某种方式失败。应该有更好的治疗方法,但是很好。

编辑:澄清一下:UnicastRemoteObject 实现了Remote。现在,

class A extends UnicastRemoteObject { void m() throws RemoteException {} }

即使 A 间接实现了 Remote,拥有类似的东西不够。您将能够实例化(即导出),但不能将其作为 A 远程传递。

您需要

interface B extends Remote { void n() throws RemoteException; }
class BImpl extends UnicastRemoteObject implements B { void n() throws RemoteException { ... } }

按照您的预期将 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 extending UnicastRemoteObject---even though that one implements Remote! 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 implements Remote. Now, having something like

class A extends UnicastRemoteObject { void m() throws RemoteException {} }

is not sufficient, even though A implements Remote indirectly. You will be able to instantiate (i.e. export), but not pass it remotely as an A.

You need to do

interface B extends Remote { void n() throws RemoteException; }
class BImpl extends UnicastRemoteObject implements B { void n() throws RemoteException { ... } }

Instances of BImpl can be passed remotely as B as you would expect. So it appears that you need to implement a distinguished remote interface aside from Remote if you want to have proper remote objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文