Search code examples
javaeclipsermiunmarshallingcodebase

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


Solution

  • 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) enter image description here