Since my early days with Java many stuff have impressed me but, among the things that impressed me the most, is the Remote Method Invocation (RMI). It makes it very easy to create applications over a network. One hard part about it was that we had to create what we call “Stub files” for each class that was published on our registry (a.k.a. Remote objects). Since JDK 5 though this was history. One of the new features was that the Stub class was generated automaticaly and no further action was needed…, or not quite like that?
Let’s break things up a little and see what was actually happening. Let’s say we have the following small server. It has a Server interface that is actually the class that extends Remote and the ServerImplementor that implements the Server (as the name says) and creates the Registry exporting the objects to it. Let’s have a look.
Server.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Server extends Remote {
public void doSomething() throws RemoteException;
}
ServerImplementor.java
import java.rmi.RemoteException;
import java.rmi.Remote;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class ServerImplementor implements Server {
public static void main(String args[]){
try{
(new ServerImplementor()).exportServer();
} catch(Exception e){
e.printStackTrace();
}
}
public void exportServer() throws Exception{
Remote obj = UnicastRemoteObject.exportObject(this, 10000);
Registry r = LocateRegistry.createRegistry(10000);
r.bind("test", obj);
}
public void doSomething() throws RemoteException{
System.out.println("hahah");
}
}
The above is a fully working example of an RMI server. On a JDK less than 1.5, that is 1.4 or smaller one would have to do “javac *.java” and then “rmic ServerImplementor.class” that would produce a file ServerImplementor_Stub.class. This is the so called Stub file.
On the client side we would have to copy the Server.class file (which is the interface that extends remote showing the services that the server has) and the ServerImplementor_Stub.class. If the Stub file was missing we would get an UnmarshalException because of the stub file missing.
So, for each build of our application, and when we develop we do that alot, we would have to rmic and then copy the files. Very frustrating if you ask me. Since JDK 1.5 Sun introduced the feature that one wouldn’t have to go through all the trouble of the stub making process. Ofcourse the client would have to have the Server.class because it would have to have a way of finding out the methods exported to the RMI registry. BUT if you try running the above example on JDK 1.5, or even on JDK 1.6, without the stub file, you would get this exception:
java.rmi.StubNotFoundException: Stub class not found: ServerImplementor_Stub; nested exception is: java.lang.ClassNotFoundException: ServerImplementor_Stub ...
Now this is quite weird huh? Once more, though, the acronym “RTFM” (Read The Fine(??) Manual) comes at hand. I discovered the solution to this by accident when i noticed the method signatures on the UnicastRemoteObject that exports the Remote object. I was, also, going through all the trouble of creating the Stub file without knowing why. So, if you have not already visited the api specification on the UnicastRemoteObject, please do so now. Scroll down to the method we used on line 18 of the ServerImplementor which is the exportObject(Remote obj). Now see the return type of the method? RemoteStub! Houston we have a problem…! Here is where all the fuss is created. Now notice the method just below that, exportObject(Remote obj, int port). This returns a pure Remote object.
Now one would say, if we get a RemoteStub is it the same with Remote? Well check the RemoteStub class. It extends the class RemoteObject which implements the Remote interface. So here it is, cloacked under the RemoteStub file creating all the trouble. So if you are among those still having problem with that, export your object on a standard port (the same you create your Registry on) and everything should work just fine.
Hope this helped clearing things out. As always comments are more than welcome!
Thanks! Very helpful, indeed!
Extremly helpful. I was moving from jdk1.4 to jdk1.6 and the need for no stub was still not clear. But do you have an idea on why this is not explicitly mentioned in the sun docs? When they say that the stub is not required i was wonderign why they have provided the rmic with the ditribution for jdk1.6
Thanx a lot. 🙂
Am glad i found this before i end up wasting hours trying to figure out what went wrong.
God… thanks a lot.
As you write… jsut read the f… manual! That’s what I keep on saying to my students 😉
Thanks! This was a great help for me!
hello,
you article is very helpful. i was very glad that i could solve this problem by using your description but i have a question. my prof used the same code as you firstly, thus with exportObject(Remote obj). If i run this code normally under eclipse it works and i don’t get an exception but if i export my codes to a jar file and run them with the cmd (i am using win 7), i got all the exceptions you described. why? why does it work with eclipse but not with the prompt?
I have no idea why. It might be because IDE’s usually take care of creating the classes you need. For instance Eclipse could be doing rmic for you automatically but that doesn’t mean that it goes in the jar file…
Helped a lot, thanks.
Thanks very much for this article. It saved my day… 🙂