title: Java RMI and ClassNotFoundException
body: <p>I am just starting to learn how to use RMI, and I have a question. I have the following directory structure:</p>
  
  <pre><code>compute.jar
  client
       |
       org\examples\rmi\client
                             |--&gt; ComputePi     // client main
                             |--&gt; Pi            // implements Task
       org\examples\rmi\compute
                             |--&gt; Compute       // interface
                             |--&gt; Task          // interface
  
  server
       |
       org\examples\rmi\engine
                             |--&gt; ComputeEngine // server main, implements Compute
       org\examples\rmi\compute
                             |--&gt; Compute       // interface
                             |--&gt; Task          // interface
  </code></pre>
  
  <p>Here's the <code>main</code> method in the <strong>ComputePi</strong> class:</p>
  
  <pre><code>if (System.getSecurityManager() == null) {
    System.setSecurityManager(new SecurityManager());
  }
  try {
    String name = "Compute";
    // args[0] = 127.0.0.1, args[1] is irrelevant
    Registry registry = LocateRegistry.getRegistry(args[0], 0);
    Compute comp = (Compute) registry.lookup(name);
    Pi task = new Pi(Integer.parseInt(args[1]));
    BigDecimal pi = comp.executeTask(task);
    System.out.println(pi);
  }
  catch (Exception e) {
    System.err.println("ComputePi exception:");
    e.printStackTrace();
  }
  </code></pre>
  
  <p>Here's the <code>main</code> method in the <strong>ComputeEngine</strong> class:</p>
  
  <pre><code>if (System.getSecurityManager() == null) {
    System.setSecurityManager(new SecurityManager());
  }
  try {
    String name = "Compute";
    Compute engine = new ComputeEngine();
    Compute stub = (Compute) UnicastRemoteObject.exportObject(engine, 0);
    Registry registry = LocateRegistry.getRegistry();
    registry.rebind(name, stub);
    System.out.println("ComputeEngine bound.");
  }
  catch (Exception e) {
    System.err.println("ComputeEngine exception: ");
    e.printStackTrace();
  }
  </code></pre>
  
  <p>Here's the <code>executeTask</code> method, also in the <strong>ComputeEngine</strong> class:</p>
  
  <pre><code>  public &lt;T&gt; T executeTask(Task&lt;T&gt; task) throws RemoteException {
      if (task == null) {
        throw new IllegalArgumentException("task is null");
      }
      return task.execute();
    }
  </code></pre>
  
  <p>The RMI registry and server start up just fine. Here are the params for the server:</p>
  
  <pre><code>C:\Users\Public\RMI\server&gt;set CLASSPATH=
  C:\Users\Public\RMI\server&gt;start rmiregistry
  C:\Users\Public\RMI\server&gt;java -Djava.rmi.server.codebase="file:/C:/Users/Public/RMI/compute.jar" -Djava.rmi.server.hostname=127.0.0.1 -Djava.security.policy=server.policy org.examples.rmi.engine.ComputeEngine
  </code></pre>
  
  <p>Here are the params for the client:</p>
  
  <pre><code>C:\Users\Public\RMI\client&gt;java -Djava.rmi.server.codebase="file:/C:/Users/Public/RMI/compute.jar" -Djava.security.policy=client.policy org.examples.rmi.client.ComputePi 127.0.0.1 45
  </code></pre>
  
  <p>However, I get the following exception when I try to run the client:</p>
  
  <pre><code>java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
          java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
          java.lang.ClassNotFoundException: org.examples.rmi.client.Pi
          at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
          at sun.rmi.transport.Transport$1.run(Unknown Source)
          at sun.rmi.transport.Transport$1.run(Unknown Source)
          at java.security.AccessController.doPrivileged(Native Method)
          at sun.rmi.transport.Transport.serviceCall(Unknown Source)
          at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
          at java.lang.Thread.run(Unknown Source)
          at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
          at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
          at sun.rmi.server.UnicastRef.invoke(Unknown Source)
          at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
          at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
          at $Proxy0.executeTask(Unknown Source)
          at org.examples.rmi.client.ComputePi.main(ComputePi.java:38)
  Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
          java.lang.ClassNotFoundException: org.examples.rmi.client.Pi
          at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
          at sun.rmi.transport.Transport$1.run(Unknown Source)
          at sun.rmi.transport.Transport$1.run(Unknown Source)
          at java.security.AccessController.doPrivileged(Native Method)
          at sun.rmi.transport.Transport.serviceCall(Unknown Source)
          at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
          at java.lang.Thread.run(Unknown Source)
  Caused by: java.lang.ClassNotFoundException: org.examples.rmi.client.Pi
          at java.net.URLClassLoader$1.run(Unknown Source)
          at java.net.URLClassLoader$1.run(Unknown Source)
          at java.security.AccessController.doPrivileged(Native Method)
          at java.net.URLClassLoader.findClass(Unknown Source)
          at java.lang.ClassLoader.loadClass(Unknown Source)
          at java.lang.ClassLoader.loadClass(Unknown Source)
          at java.lang.Class.forName0(Native Method)
          at java.lang.Class.forName(Unknown Source)
          at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
          at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
          at java.rmi.server.RMIClassLoader$2.loadClass(Unknown Source)
          at java.rmi.server.RMIClassLoader.loadClass(Unknown Source)
          at sun.rmi.server.MarshalInputStream.resolveClass(Unknown Source)
          at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
          at java.io.ObjectInputStream.readClassDesc(Unknown Source)
          at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
          at java.io.ObjectInputStream.readObject0(Unknown Source)
          at java.io.ObjectInputStream.readObject(Unknown Source)
          at sun.rmi.server.UnicastRef.unmarshalValue(Unknown Source)
          ... 11 more
  </code></pre>
  
  <p>But if I add the <strong>Pi.class</strong> file to the server directory:</p>
  
  <pre><code>server
       |
       org\examples\rmi\engine
                             |--&gt; ComputeEngine // server main, implements Compute
       org\examples\rmi\compute
                             |--&gt; Compute       // interface
                             |--&gt; Task          // interface
       org\examples\rmi\client
                             |--&gt; Pi            // same as Pi for client
  </code></pre>
  
  <p>The program works. My question is, does <strong>Pi.class</strong> really need to be on the server for my program to work? My understanding is (and please correct me if I'm wrong) that I send an instance of that class to the server, and the server would know what to do with it, i.e. it doesn't care about the implementation. Can someone explain how RMI is working in my case? I really appreciate it. Thanks!</p>