I have instantized a class that implements Serializable and I am trying to stream that object like this:
try{
Socket socket = new Socket("localhost", 8000);
ObjectOutputStream toServer = new ObjectOutputStream(socket.getOutputStream());
toServer.writeObject(myObject);
} catch (IOException ex) {
System.err.println(ex);
}
All good so far right? Then I am trying to read the fields of that object like this:
//This is an inner class
class HandleClient implements Runnable{
private ObjectInputStream fromClient;
private Socket socket; // This socket was established earlier
try {
fromClient = new ObjectInputStream(socket.getInputStream());
GetField inputObjectFields = fromClient.readFields();
double myFristVariable = inputObjectFields.get("myFirstVariable", 0);
int mySecondVariable = inputObjectFields.get("mySecondVariable", 0);
//do stuff
} catch (IOException ex) {
System.err.println(ex);
} catch (ClassNotFoundException ex) {
System.err.println(ex);
} finally {
try {
fromClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
But I always get the error:
java.io.NotActiveException: not in call to readObject
This is my first time streaming objects instead of primitive data types, what am I doing wrong?
BONUS
When I do get this working correctly, is the ENTIRE CLASS passed with the serialized object (i.e. will I have access to the methods of the object’s class)? My reading suggests that the entire class is passed with the object, but I have been unable to use the objects methods thus far. How exactly do I call on the object’s methods?
In addition to my code above I also experimented with the readObject method, but I was probably using it wrong too because I couldn’t get it to work. Please enlighten me.
To answer your first question:
You need to use
ObjectInputStream.readObjectto deserialize. You cannot read individual fields from the stream*.Don’t forget to flush the output stream when writing!
The second question is a little more complex. What the serialization mechanism does is write a class identifier to the stream followed by the serialized object data. When it deserializes it will read the class identifier and attempt to load that class (if it isn’t already loaded). It will then instantiate the object using the no-arg constructor and call the private
readObject(ObjectInputStream)method. Yes, that’s right, it calls a private method from outside the class. Java serialization is special.If the class cannot be found (i.e. if it’s not on the classpath) then an exception will be thrown; otherwise you’ll get a fully deserialized object of the correct type assuming no other errors are found.
For example, suppose you have the following classes:
Now suppose you put those classes into three jars (one class per jar): server.jar, client.jar and data.jar. If you run the following commands then it should all work:
But if you do this:
then you’ll get a
ClassNotFoundExceptionbecause the client doesn’t know how to find theDataclass.Long story short: the class itself is not written to the stream. If deserialization succeeds then you will have access to the object as though it had been created locally, but you will have to downcast the result of
readObjectto the expected type.There is some complexity around versioning that I’ve ignored for now. Take a look at
serialVersionUIDand how to deal with changes to serializable classes if versioning is likely to be an issue.*Not strictly true. You can call
readFieldsinside the serializable object’sreadObjectmethod (orreadResolve), but you cannot call it from outside the deserialization mechanism. Does that make sense? It’s a little hard to explain.