aspose file tools*
The moose likes I/O and Streams and the fly likes subclasses throw null exception when using objectoutput stream Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » I/O and Streams
Bookmark "subclasses throw null exception when using objectoutput stream" Watch "subclasses throw null exception when using objectoutput stream" New topic
Author

subclasses throw null exception when using objectoutput stream

Chad Schultz
Greenhorn

Joined: Mar 25, 2007
Posts: 23
Here's the problem that's had me banging my head against the wall for two days now. For a homework assignment (my teacher actually recommended this site) I need a client and server. I'm using an objectOutputStream and objectInputStream to communicate between them by sending special strings and objects. The client has a GUI. When I click a button, it needs to send and receive the proper objects. (The event handlers are subclasses of the Client class.) The event handler, however, is apparently unable to access the object stream. Although it works just fine in the class methods, the subclasses throw an exception whenever they try to access it in any way. It isn't an InvalidClassException, IOException, or NotSerializableException, which is what the API documentation says it should throw. It's a general exception. The message for the exception? Null. Any thoughts on how to fix this would be greatly apperciated!
Keith Lynn
Ranch Hand

Joined: Feb 07, 2005
Posts: 2367
Could you post the code?
Chad Schultz
Greenhorn

Joined: Mar 25, 2007
Posts: 23
Here's the code! It's not the prettiest just yet... I've been mangling and messing with it for quite a while, trying to resolve the issue.

/* SERVER.JAVA */
// Import statements make it possible to reference required packaged code.

import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

// This class defines a server that allows connection of multiple clients
// to access a shared file of employee data.
// ---- Written by: Jon Huhtala
// ---- Modified by: Chad Schultz

public class Server {

// Variables

String path = "c:/temp/employees.txt"; // Path of disk file
Map employees = new TreeMap(); // The employee collection
Employee emp; // The current Employee object
int port = 7000; // Port number
int loginNumber = 0; // For counting logins
ArrayList threads; // For storing thread references
JPanel panel; // Component panel
TextArea message; // For Scrolling message area
JFrame frame; // Reference for main window
JButton exit; // EXIT button

// Main method to create a Server object and begin its processing.

public static void main(String[] args) {
new Server().go();
}

// This method builds the server GUI, reads data from disk and loads
// it into the collection, establish a port, and receive client logins.

public void go() {

// Build the GUI.

frame = new JFrame("Server");
frame.setSize(350, 275);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(new JLabel("Server Status and Messages"));
message = new TextArea("", 10, 40, TextArea.SCROLLBARS_VERTICAL_ONLY);
message.setBackground(Color.black);
message.setForeground(Color.yellow);
panel.add(message);
exit = new JButton("EXIT");
exit.addActionListener(new ExitListener());
panel.add(exit);
frame.getContentPane().add(panel);
frame.setVisible(true);

// Read data from disk and load the collection.

try {
FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
while (line != null) {
StringTokenizer parser = new StringTokenizer(line, ",");
ArrayList fields = new ArrayList();
while (parser.hasMoreTokens()) {
fields.add(parser.nextToken());
}
System.out.println("Employee number " + fields.get(0) + ": " + fields.get(1));
employees.put(fields.get(0),fields.get(1));
line = br.readLine();
}
System.out.println("End of file");
br.close();
message.append("Collection loaded" + "\n");
}
catch (IOException err) {
System.out.println(err.getMessage());
}

// Establish a port and accept client logins.

try {
ServerSocket ss = new ServerSocket(port);
message.append("Server active" + "\n");
message.append("Address: " + InetAddress.getLocalHost() + "\n");
message.append("Port: " + port + "\n");
threads = new ArrayList();
while (true) {
Socket s = ss.accept();

// Create a thread to process requests from the client, add it
// to the list of threads, and start its processing.

ServerThread thread = new ServerThread(s, loginNumber);
threads.add(thread);
thread.start();
loginNumber++;
}
}
catch(IOException err) {
message.append(err.getMessage() + "\n");
}
}

// This inner class defines an action listener for the exit button.

class ExitListener implements ActionListener {

// When the button is clicked, all active threads are killed, data
// is written back to disk from the collection in ascending employee
// number order, and the server is shutdown.

public void actionPerformed(ActionEvent e) {
for (int i = 0; i < threads.size(); i++) {
((ServerThread)threads.get(i)).kill();
threads.remove(i);
}
Iterator p = employees.keySet().iterator();
try {
FileWriter fw = new FileWriter(path);
BufferedWriter bw = new BufferedWriter(fw);
System.out.println("Writing employees to disk...");
while (p.hasNext()) {
emp = (Employee) employees.get(p.next());
System.out.println(emp.getNumber() + " - " + emp.getName());
bw.write(emp.getNumber() + "," + emp.getName());
bw.newLine();
}
bw.close();
System.out.println("Closed for output");
}
catch (IOException err) {
message.append(err.getMessage() + "\n");
}
frame.dispose();
System.exit(0);
}
}

// This inner class encapsulates the thread processing for a single client.

class ServerThread extends Thread {

// Variables

boolean alive; // For continuing thread processing
int threadNum; // For holding assigned thread number
Socket s; // Reference for the thread's Socket
ObjectOutputStream toClient; // For writing objects to the client
ObjectInputStream fromClient; // For reading objects from the client

// This constructor initializes the ServerThread object, creates
// object streams for communicating with the client, and sends the
// client its Integer thread number.

public ServerThread(Socket mySocket, int myThreadNum) {
s = mySocket;
threadNum = myThreadNum;
try {
toClient = new ObjectOutputStream(s.getOutputStream());
fromClient = new ObjectInputStream(s.getInputStream());
toClient.writeObject(new Integer(threadNum));
toClient.flush();
message.append("Thread " + threadNum + ": Connected" + "\n");
/*Employee e;
e = (Employee)fromClient.readObject();
System.out.println((String)e.getName());*/
}
catch(IOException err) {
message.append("Thread " + threadNum + ": " + err.getMessage() + "\n");
}
catch(Exception err) { System.out.println("Heh heh. Oops");}
}

// This method defines thread processing with the client. The thread is
// marked as being alive, then it loops to handle client requests until
// it is killed.

public void run() {
alive = true;
while (alive) {
try {
String request = (String)fromClient.readObject();

// Processing for a "FIND" request.

if (request.equals("FIND")) {

// Read the employee number from the client. If it matches that
// of an existing employee, get the Employee object from the
// collection and send it to the client. Otherwise, send a "dummy"
// Employee object to indicate that the requested employee was
// not found.

Integer empNum = (Integer)fromClient.readObject();
if (employees.containsKey(empNum)) {
emp = (Employee)employees.get(empNum);
toClient.writeObject(emp);
toClient.flush();
message.append("Thread " + threadNum + ": FOUND employee " +
emp.getNumber() + "\n");
}
else {
toClient.writeObject(new Employee(0, ""));
toClient.flush();
message.append("Thread " + threadNum +
": DID NOT FIND employee " +
empNum.intValue() + "\n");
}
}

// Processing for an "ADD" request.

else if (request.equals("ADD")) {

// Read the Employee object from the client. If an employee
// with a matching employee number already exists, send an error
// String to the client. Otherwise, put the Employee object into the
// collection and send a verification String to the client.

emp = (Employee)fromClient.readObject();
if (safeUpdate() == false) {
toClient.writeObject("NOT ADDED");
toClient.flush();
message.append("Thread " + threadNum +
": DID NOT ADD employee " +
emp.getNumber() + "\n");
}
else {
toClient.writeObject("ADDED");
toClient.flush();
message.append("Thread " + threadNum + ": ADDED employee " +
emp.getNumber() + "\n");
}
}

// Processing for a "DISCONNECT" request.

else if (request.equals("DISCONNECT")) {
alive = false;
message.append("Thread " + threadNum + ": DISCONNECTING" + "\n");
}

// Processing for an invalid request. The thread is killed due to
// the difficulty of re-synchronizing client communications.

else {
alive = false;
message.append("Thread " + threadNum +
": INVALID: " + request + "\n");
}
}
catch (Exception err) {
alive = false;
message.append("Thread " + threadNum + ": " +
err.getMessage() + "\n");
}
}

// Close the object streams as thread processing ends.

try {
fromClient.close();
toClient.close();
message.append("Thread " + threadNum + ": DISCONNECTED" + "\n");
}
catch (Exception err) {
message.append("Thread " + threadNum + ": " + err.getMessage() + "\n");
}
}

// This method can be called to kill the thread's processing loop.

public void kill() {
alive = false;
}

// This method can be called to safely update the collection in a
// multithreaded environment.

public synchronized boolean safeUpdate() {
if (employees.containsKey(new Integer(emp.getNumber()))) {
return false;
}
else {
employees.put(new Integer(emp.getNumber()), emp);
return true;
}
}
}
}

// This class encapsulates the data and processing of an employee.
// ---- Written by: Jon Huhtala

class Employee implements Serializable {

// Instance variables

private int number;
private String name;

// This constructor will initialize employee data to values supplied by
// the caller. No editing is performed (let's hope they get it right).

public Employee(int iNumber, String iName) {
number = iNumber;
name = iName;
}

// These "getter" methods will return the corresponding employee data.

public int getNumber() {
return number;
}
public String getName() {
return name;
}
}












/* CLIENT.JAVA */
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import javax.swing.event.*;
public class Client {
JFrame frame;
JPanel panel;
JTextField empNum;
JTextField empName;
JButton find;
JButton add;
JButton exit;
ObjectInputStream fromServer;
ObjectOutputStream toServer;
Employee emp;
boolean disconnect;
int threadNum;
public static void main(String[] args) {
Client me = new Client();
me.go();
}
public void go() {
disconnect = false;
frame = new JFrame("Client");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 120);
panel = new JPanel();
frame.getContentPane().add(panel);
panel.add(new JLabel("Employee number:"));
empNum = new JTextField(15);
panel.add(empNum);
panel.add(new JLabel("Employee name:"));
empName = new JTextField(16);
panel.add(empName);
find = new JButton("Find");
find.addActionListener(new FindListener());
panel.add(find);
add = new JButton("Add");
add.addActionListener(new AddListener());
panel.add(add);
exit = new JButton("Exit");
exit.addActionListener(new ExitListener());
panel.add(exit);
frame.setVisible(true);
try {
Socket s = new Socket("localhost", 7000);
ObjectInputStream fromServer = new ObjectInputStream(s.getInputStream());
ObjectOutputStream toServer = new ObjectOutputStream(s.getOutputStream());
threadNum = (Integer)fromServer.readObject();
int i = 0;
System.out.println("Thread number: " + threadNum);
System.out.println("Connected to server");
/*emp = new Employee(99,"HI Lois");
toServer.writeObject(emp);
toServer.flush();*/
do {
// i++;
} while (!disconnect);
// } while (i < 3);
fromServer.close();
toServer.close();
System.out.println("Connection is closed");
}
catch(Exception err) {
System.out.println(err.getMessage());
}
}


//Code for the "Find" button. This sends the employee number to the server
//and receives an Employee object, which it display unless the employee
//number is 0, representing that no match was found. In that case,
//an error message is displayed instead of the employee's name.
// -Chad Schultz
public class FindListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String cmd = new String("FIND");
Integer n;
try {
n = new Integer(Integer.parseInt(empNum.getText()));
}
catch (NumberFormatException err) {
empName.setText("Need a number in employee number field- like so");
empNum.setText("17");
n = 17;
}
//emp = new Employee(99,"HI Lois");
try {
toServer.close();
// toServer.writeObject(new Employee(5,"hello world"));
toServer.writeObject(cmd);
//toServer.writeObject(emp);
System.out.println("Sent cmd: " + cmd);
toServer.flush();
toServer.writeObject(n);
toServer.flush();
emp = (Employee)fromServer.readObject();
System.out.println("emp name: " + emp.getName());
System.out.println("emp number: " + emp.getNumber());
if (emp.getNumber() == 0)
empName.setText("NO MATCH FOUND");
else {
empNum.setText(""+emp.getNumber());
empName.setText(emp.getName());
}
}
catch(InvalidClassException err) {
System.out.println("InvalidClass");
}
catch(NotSerializableException err) {
System.out.println("Not serializable");
}
catch(IOException err) {
System.out.println("IO Exception");
}
catch(Exception err) {
System.out.println("Woopsie!");
System.out.println(err.getLocalizedMessage());
}
}
}

// -Chad Schultz
public class AddListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
toServer.writeObject((String)"ADD");
// toServer.flush();
toServer.writeObject(new Employee(Integer.parseInt(empNum.getText()),empName.getText()));
toServer.flush();
empName.setText((String)fromServer.readObject());
}
catch(Exception err) {
System.out.println(err.getMessage());
}
}
}

// -Chad Schultz
public class ExitListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
disconnect = true;
try {
toServer.writeObject((String)"DISCONNECT");
/* fromServer.close();
toServer.close();
System.out.println("Connection is closed");*/
}
catch(Exception err) {
System.out.println(err.getMessage());
}
frame.dispose();
System.exit(0);
}
}

}

// This class encapsulates the data and processing of an employee.
// ---- Written by: Jon Huhtala

class Employee implements Serializable {

// Instance variables

private int number;
private String name;

// This constructor will initialize employee data to values supplied by
// the caller. No editing is performed (let's hope they get it right).

public Employee(int iNumber, String iName) {
number = iNumber;
name = iName;
}

// These "getter" methods will return the corresponding employee data.

public int getNumber() {
return number;
}
public String getName() {
return name;
}
}
Keith Lynn
Ranch Hand

Joined: Feb 07, 2005
Posts: 2367
Can you print out the stack trace that you get when the error occurs? That can help pinpoint the problem.
Chad Schultz
Greenhorn

Joined: Mar 25, 2007
Posts: 23
Okay. I'll try and see if I can figure out how to do that. I'm a Java newbie, so I'm not really sure what the strack trace is or how to get it. I'm using the NetBeans IDE, which has a "Call Stack" section in the debugger. There seems to be no different in this before or after a problematic line: it says
Client$FindListener.actionPerformed:93
And then a long list of "hidden calls" which refuse to let me copy and paste them. If you were looking for something else, let me know what it is and how to find it. Thanks!
Keith Lynn
Ranch Hand

Joined: Feb 07, 2005
Posts: 2367
I was able to compile and run your code, and it looks like your problem is a simple shadowing.

Take a look at this line in the method go() in Client.java.



You declare the variables fromServer and toServer as instance variables in the class Client.java, but you redeclare them here in the try block. So when the try block exits, the instance variables fromServer and toServer are still null.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: subclasses throw null exception when using objectoutput stream