简体   繁体   中英

RMI UnmarshalException in server

I've tried to replicate the tutorial in http://www.ejbtutorial.com/java-rmi/a-step-by-step-implementation-tutorial-for-java-rmi on Eclipse (on Windows 7 x64).

I simply copied the code, so, supposing it is all done correctly, it should work.

I had to change the path variable because rmic or start rmiregistry didn't work in each folder. Now my path variable is like this:

C:\Program Files\Java\jdk1.7.0_25\bin;C:\OCaml\bin;C:\Program Files (x86)\EasyPH
P-DevServer-13.1VC11\binaries\php\php_runningversion;C:\Program Files (x86)\NVID
IA Corporation\PhysX\Common;C:\Windows\system32;C:\Windows;C:\Windows\System32\W
bem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Nmap

I added "C:\\Program Files\\Java\\jdk1.7.0_25\\bin" at the beginning. Now when i open cmd and digit start rmiregistry it works fine.

The problem is that when i try to run the server on Eclipse, after having started rmiregistry on cmd, it doesn't work and appears:

Addition Server failed: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
java.lang.ClassNotFoundException: AdditionInterface

I set the codebase as in the tutorial, so i really don't understand what's going on... Any suggestion is really appreciated. Thanks in advance.

Here's the stacktrace:

    java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: AdditionInterface
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:419)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at sun.rmi.transport.Transport$1.run(Transport.java:174)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:377)
    at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
    at java.rmi.Naming.rebind(Naming.java:177)
    at AdditionServer.main(AdditionServer.java:10)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: AdditionInterface
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:409)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at sun.rmi.transport.Transport$1.run(Transport.java:174)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
    Caused by: java.lang.ClassNotFoundException: AdditionInterface
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.rmi.server.LoaderHandler$Loader.loadClass(LoaderHandler.java:1208)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:270)
    at sun.rmi.server.LoaderHandler.loadClassForName(LoaderHandler.java:1221)
    at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:731)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:675)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:612)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:646)
    at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:311)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:263)
    at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1556)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1512)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    ... 13 more

Edit: note that even doing the rmic of the Addition class, creating the stub, there's always the unmarshallException, even if on Addition_Stub and not on AdditionInterface

RMI is hard to use thing. Too many security issues, too many open ports and too easy to broke.

But as decision i can recommend you move interfaces and translated by RMI classes to one small jar file, pass it to rmiregistry and don't set codebase property.

Command to start rmiregistry, you should set full path to your jar here:

rmiregistry -J-classpath -J/home/user/dev/project/project-iface.jar

When you start server, bind it to existed rmiregistry , not start its own. For client use exactly the same jar with interface classes, which used when start rmiregistry .

That allow you avoid problems with remote class loading, but adds complicity to development process, if your interface classes changes often.

Related to your example, you should do next steps:

  1. Create another project in eclipse, move file AdditionInterface.java into that project. Project should compiles in jar. Name it iface.jar or something like that.
  2. Remove AdditionInterface from client and serverside project.
  3. Add iface.jar as dependency for both client and server.
  4. Remove unnecessary file security.policy from both client and server.
  5. Remove VM arguments to run client and server.
  6. Remove line System.setSecurityManager(new RMISecurityManager()); from client and server code.
  7. Build artifact iface.jar
  8. Run command in cmd: rmiregistry -J-classpath -J/home/grigory/dev/test24804087/out/artifacts/iface_jar/iface.jar
  9. Start server, you should get message "Addition Server is ready."
  10. Run client. You should get message "Result is :19"

Example with project structure (for IDEA) 在此处输入图片说明

RMI Class Loading is not supposed to load via RMI interface but from external resource eg URL in web (that is what codebase is pointing to).

So if you have some classes on your server side, you either has to have the same classes on classpath of client application, or publicly available as web resource and vice versa.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM