The question is published on by Tutorial Guruji team.
Trying to write a program that will allow clients to send an object to each other. I’m currently using the ObjectOuptutStream to send it across sockets and whenever I try to read or write an object from the object stream, it gives the exception: java.io.NotSerializableException. I searched online about this exception, and the solution I am getting mostly was to implement the Serializable interface on the object you are sending or reading from the stream. Which I did, but still receives this exception.
Here’s the object class:
public class Event implements Serializable { private static final long serialVersionUID = 1L; Integer from; Vector<Integer> timestamp; public Event(int identifier, Vector<Integer> timestamp) { this.from = identifier; this.timestamp = timestamp; } int getFromID() { return from; } Vector<Integer> getTimestamp() { return timestamp; } }
Here’s the section of the Client class that is writing to other sockets
Random rand = new Random(); int temp; while (eventCount < 100) { System.out.println("Generating Event"); int choice = rand.nextInt(5); if (choice == 0) { temp = timestamp.get(identifier); ++temp; timestamp.set(identifier, temp); } else { int randC = rand.nextInt(outputClients.size()); ClientSocket cc = outputClients.get(randC); cc.out.writeObject(new Event(identifier, timestamp)); } System.out.println("Done Generating Event"); }
And here’s the threads that are reading the object
public class ClientConnection extends Thread { Socket socket; ObjectOutputStream out; ObjectInputStream in; Random rand = new Random(); public ClientConnection(Socket s) { this.socket = s; try { out = new ObjectOutputStream (socket.getOutputStream()); in = new ObjectInputStream (socket.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } // execute the event private void executeEvent(int from, Vector<Integer> x) { int temp; synchronized (timestamp) { for (int i = 0; i < timestamp.size(); ++i) { if (x.get(i) > timestamp.get(i)) { timestamp.set(i, x.get(i)); } } temp = timestamp.get(from); ++temp; timestamp.set(from, temp); } } @Override public void run () { while (true) { System.out.println("Reading events"); if (!isAlive) { break; } try { Event event = (Event) in.readObject(); executeEvent(event.getFromID(), event.getTimestamp()); } catch (ClassNotFoundException e) { } catch (IOException e) { e.printStackTrace(); } System.out.println(timestamp); } } }
And here’s the Client class for full context (assuming all the appropriate packages are imported)
public class Computer { static final int MAX_SYSTEMS = 2; // MAX SYSTEMS static Vector<Integer> timestamp = new Vector<Integer>(); static int[] timestamp1 = new int[MAX_SYSTEMS]; // Time-stamp static int identifier; // Computer ID static int eventCount = 0; // Event Counts static boolean isAlive = true; // Check if the computer is alive Socket sockToServer; PrintWriter outputToServer; BufferedReader inputFromServer; String textFromServer; ServerSocket ss; static ArrayList<ClientSocket> outputClients = new ArrayList<ClientSocket>(); static ArrayList<ClientConnection> inputClients = new ArrayList<ClientConnection>(); Log log; public static void main(String[] args) throws IOException { new Computer("127.0.0.1", 8000); } public Computer(String hostname, int port) throws IOException { // Instantiate server socket int socketPort = port + identifier + 1; System.out.println(socketPort); ss = new ServerSocket(socketPort); System.out.println("Server Socket Instantiated"); // Creating sockets (with streams) to write to stream for (int i = 0; i < MAX_SYSTEMS; ++i) { if (i != identifier) { Socket thing1 = new Socket(hostname, port + i + 1); ClientSocket cs = new ClientSocket (thing1); outputClients.add(cs); } } log.write("Client Sockets Instantiatedn"); // Create threads for reading objects and updating timestamp for (int i = 0; i < MAX_SYSTEMS - 1; ++i) { ClientConnection clientConn = new ClientConnection(ss.accept()); clientConn.start(); inputClients.add(clientConn); } log.write("Server connected to clients"); Random rand = new Random(); // Writing Events int temp; while (eventCount < 100) { System.out.println("Generating Event"); int choice = rand.nextInt(5); if (choice == 0) { temp = timestamp.get(identifier); ++temp; timestamp.set(identifier, temp); } else { int randC = rand.nextInt(outputClients.size()); ClientSocket cc = outputClients.get(randC); cc.out.writeObject(new Event(identifier, timestamp)); } System.out.println("Done Generating Event"); } log.write("Computer finished generating events. Continue listening...n"); outputToServer.println("Finish"); // Wait for Tear Down Message while (true) { try { textFromServer = inputFromServer.readLine(); if (textFromServer.equals("Tear Down")) { isAlive = false; break; } } catch (IOException e) { e.printStackTrace(); } } log.write("Computer shutting off...."); for (int i = 0; i < outputClients.size(); ++i) { ClientSocket sc = outputClients.get(i); sc.socket.close(); } sockToServer.close(); } // client socket class (organizing) public class ClientSocket { Socket socket; ObjectOutputStream out; ObjectInputStream in; public ClientSocket(Socket s) { try { this.socket = s; this.out = new ObjectOutputStream(socket.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } System.out.println("Client Socket Created"); } } public class Event implements Serializable { private static final long serialVersionUID = 1L; Integer from; Vector<Integer> timestamp; public Event(int identifier, Vector<Integer> timestamp) { this.from = identifier; this.timestamp = timestamp; } int getFromID() { return from; } Vector<Integer> getTimestamp() { return timestamp; } } // send event thread public class ClientConnection extends Thread { Socket socket; ObjectOutputStream out; ObjectInputStream in; Random rand = new Random(); public ClientConnection(Socket s) { this.socket = s; try { out = new ObjectOutputStream (socket.getOutputStream()); in = new ObjectInputStream (socket.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } // execute the event private void executeEvent(int from, Vector<Integer> x) { int temp; synchronized (timestamp) { for (int i = 0; i < timestamp.size(); ++i) { if (x.get(i) > timestamp.get(i)) { timestamp.set(i, x.get(i)); } } temp = timestamp.get(from); ++temp; timestamp.set(from, temp); } } @Override public void run () { while (true) { System.out.println("Reading events"); if (!isAlive) { break; } try { Event event = (Event) in.readObject(); executeEvent(event.getFromID(), event.getTimestamp()); } catch (ClassNotFoundException e) { } catch (IOException e) { e.printStackTrace(); } System.out.println(timestamp); } } } }
TL;DR Trying to read and write object through sockets using Object(Output/Input)Stream object. When I do so, I get the NotSerializableException, even though I implemented the Serializable interface in the class that was being written and read from the stream.
All help is appreciated!
(edit: stacktrace)
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: timetableexchange.Computer at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.defaultReadFields(Unknown Source) at java.io.ObjectInputStream.readSerialData(Unknown Source) at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source) at timetableexchange.Computer$ClientConnection.run(Computer.java:239) Caused by: java.io.NotSerializableException: timetableexchange.Computer at java.io.ObjectOutputStream.writeObject0(Unknown Source) at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source) at java.io.ObjectOutputStream.writeSerialData(Unknown Source) at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source) at java.io.ObjectOutputStream.writeObject0(Unknown Source) at java.io.ObjectOutputStream.writeObject(Unknown Source) at timetableexchange.Computer.<init>(Computer.java:128) at timetableexchange.Computer.main(Computer.java:39) java.io.NotSerializableException: timetableexchange.Computer at java.io.ObjectOutputStream.writeObject0(Unknown Source) at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source) at java.io.ObjectOutputStream.writeSerialData(Unknown Source) at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source) at java.io.ObjectOutputStream.writeObject0(Unknown Source) at java.io.ObjectOutputStream.writeObject(Unknown Source) at timetableexchange.Computer.<init>(Computer.java:128) at timetableexchange.Computer.main(Computer.java:39)
Answer
Now that you have supplied the stacktrace …. I see the problem!
You have created Event
as an inner class of Computer
. That means that an Event
has an implicit link to the enclosing Computer
instance … which will be serialized along with the Event
instance.
But Computer
is not Serializable
.
A (probably incorrect) solution would be to make Computer
implement Serializable
. But that means you would send an instance of Computer
with every separately serialized Event
… which is why it is probably wrong.
A better solution would be to declare Event
as static
so that it doesn’t have a reference to the enclosing Computer
. As far as I can see, it doesn’t need to be an “inner” class. It could just be a “nested” class, or even a top-level class.
Advice: When you use nested and inner classes, make sure that you indent them correctly … to make it easier for other people to spot what is going on.