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 Instantiated\n");
// 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)
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.