annotateClass replaceObject RMI Customizes the Serialization Algorithm

protected boolean enableReplaceObjectboolean enable protected Object replaceObjectObject obj protected void drain protected void writeObjectOverrideObject obj protected void writeClassDescriptorObjectStreamClass classdesc protected void writeStreamHeader These all have default implementations in ObjectOutputStream . That is, annotateClass and annotateProxyClass do nothing. enableReplaceObject returns false , and so on. However, these methods are still called during serialization. And RMI, by overriding these methods, customizes the serialization process. The three most important methods from the point of view of RMI are: protected void annotateClassClass cl protected boolean enableReplaceObjectboolean enable protected Object replaceObjectObject obj Lets describe how RMI overrides each of these.

10.4.3.1 annotateClass

ObjectOutputStream calls annotateClass when it writes out class descriptions. Annotations are used to provide extra information about a class that comes from the serialization mechanism and not from the class itself. The basic serialization mechanism has no real need for annotations; most of the information about a given class is already stored in the stream. RMIs dynamic classloading system uses annotateClass to record where .class files are stored. Well discuss this more in Chapt er 19 . RMI, on the other hand, uses annotations to record codebase information. That is, RMI, in addition to recording the class descriptions, also records information about the location from which it loaded the classs bytecode. Codebases are often simply locations in a filesystem. Incidentally, locations in a filesystem are often useless information, since the JVM that deserializes the instances may have a very different filesystem than the one from where the instances were serialized. However, a codebase isnt restricted to being a location in a filesystem. The only restriction on codebases is that they have to be valid URLs. That is, a codebase is a URL that specifies a location on the network from which the bytecode for a class can be obtained. This enables RMI to dynamically load new classes based on the serialized information in the stream. Well return to this in Chapt er 19 .

10.4.3.2 replaceObject

The idea of replacement is simple; sometimes the instance that is passed to the serialization mechanism isnt the instance that ought to be written out to the data stream. To make this more concrete, recall what happened when we called rebind to register a server with the RMI registry. The following code was used in the bank example: Account_Impl newAccount = new Account_ImplserverDescription.balance; Naming.rebindserverDescription.name, newAccount; System.out.printlnAccount + serverDescription.name + successfully launched.; This creates an instance of Account_Impl and then calls rebind with that instance. Account_Impl is a server that implements the Remote interface, but not the Serializable interface. And yet, somehow, the registry, which is running in a different JVM, is sent something. What the registry actually gets is a stub. The stub for Account_Impl , which was automatically generated by rmic , begins with: public final class Account_Impl_Stub extends java.rmi.server.RemoteStub java.rmi.server.RemoteStub is a class that implements the Serializable interface. The RMI serialization mechanism knows that whenever a remote server is sent over the wire, the server object should be replaced by a stub that knows how to communicate with the server e.g., a stub that knows on which machine and port the server is listening. Calling Naming.rebind actually winds up passing a stub to the RMI registry. When clients make calls to Naming.lookup , as in the following code snippet, they also receive copies of the stub. Since the stub is serializable, theres no problem in making a copy of it: _account = AccountNaming.lookup_accountNameField.getText ; In order to enable this behavior, ObjectOutputStream calls enableReplaceObject and replaceObject during the serialization process. In other words, when an instance is about to be serialized, ObjectOutputStream does the following: 1. It calls enableReplaceObject to see whether instance replacement is enabled. 2. If instance replacement is enabled, it calls replaceObject , passing in the instance it was about to serialize, to find out which instance it should really write to the stream. 3. It then writes the appropriate instance to the stream.

10.4.4 Maintaining Direct Connections