ClassCastExceptions....

Hi folks.

I'm trying to write a class that allows an administrator to add users to given application. This class has an instance of User class, which has the usual sets and gets etc.

My problem arises in the UserList class (which will be pasted below.) I've manged to write to a file with out any trouble at all, however I want the program to load the file up on start up, so rather than re-write the file each time, the program will add users to the file.

My intention is to load the file as an object, and this put it all in a vector. However the read code doesn't seem to work.

The program as it is will compile, I've added the user class to the bottom of it as well, as those are the only two classes that are needed.

Any help would be greatfully recieved

UserList.java

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.BufferedReader;

import java.io.EOFException;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

import java.util.Collections;

import java.util.Vector;

/**

* Class - UserList

*

* @see ToDoList class

*

* This class is loosly based on the to do list class.

*

* @author Emyr Williams

*

* Code HistoryVersion Number

* ====================================================

* 23/10/06 - Date of Birth of code0.0.1a*

* 24/10/06 - File I/O functions added0.0.1b*

* ====================================================

*/

publicclass UserListimplements Serializable

{

User user =null;

Vector<User> users =new Vector<User>();

int index = 0;

String userName;

String passwd;

boolean isAdmin =false;

/**

* Method - addUser

*

* Will add a user to the user list, and then the new user will

* be written to the file soon as the administrator clicks on

* apply.

*/

publicvoid addUser()throws IOException

{

for(;;)

{

user = readUser();

if(user ==null)

{

break;

}

users.add(user);

}

}

// reads the user input from the keyboard.

public User readUser()throws IOException

{

String s =null;

String name =null;

String pass =null;

boolean admin =false;

BufferedReader input =new BufferedReader(new InputStreamReader(System.in));

System.out.println("Please Enter the user name: (! to store the user)");

name = input.readLine().trim();

if(name.charAt(0)=='!')

{

writeToFile();

displayUserList();

returnnull;

}

System.out.println("Please enter the user password: ");

pass = input.readLine().trim();

returnnew User(name, pass);

}

publicvoid displayUserList()

{

System.out.println("User Name \t\t" +"Password");

System.out.println("======================================================");

Collections.sort(users);

for(User user : users)

{

System.out.println(user);

}

}

public String[] toArray()

{

String[] titles =new String[users.size()];

for(int x = 0; x < users.size(); x++)

{

titles[x] = users.get(x).getUserName();

}

return titles;

}

/**

* Method - writeToFile

* @param - Takes a file object as it's parameter so the program

* can know where the file is going to be held.

*

* This method will be used everytime an administrator adds

* a new user to the user list.

*

*/

publicvoid writeToFile()

{

File theFile =new File("users.dat");

ObjectOutputStream objectOut =null;

try

{

objectOut =new ObjectOutputStream(new BufferedOutputStream

(new FileOutputStream(theFile)));

objectOut.writeObject(users);

System.out.println("File written");

}

catch(IOException e)

{

System.err.println(e);

System.exit(0);

}

try

{

objectOut.close();

}

catch(IOException e)

{

e.printStackTrace(System.err);

System.exit(1);

}

}

/**

* Method - loadUserList

*

* This method will be executed when the program starts, and then

* the input from the GUI will be compared with the data in that's

* inputed by the user. Then if the login is successful, the appropriate

* screen will then pop up, and the operator can get to work.

*

* @return - Returns a file (I think)

*/

publicvoid loadUserList()

{

ObjectInputStream objectIn =null;

try

{

objectIn =new ObjectInputStream(new BufferedInputStream

(new FileInputStream("C:/Java/pos/src/users.dat")));

while(true)

{

// I get a ClassCastException here.

// the API tells me that it's something to cast

// an object to a subclass of which it is not an instance

// I'm not sure how I've done this.

user = (User)objectIn.readObject();

System.out.println(user);

// add the contents of the file to the users vector

}

}

catch(EOFException e)

{

e.printStackTrace(System.err);

}

catch(ClassNotFoundException ef)

{

ef.printStackTrace(System.err);

}

catch(IOException eof)

{

eof.printStackTrace(System.err);

}

try

{

objectIn.close();

}

catch(IOException e)

{

e.printStackTrace();

}

}

publicvoid clearScreen()

{

for(int i = 0; i < 5; i++)

{

System.out.println("");

}

}

publicstaticvoid main(String [] args)throws IOException, ClassNotFoundException

{

UserList list1 =new UserList();

list1.loadUserList();

list1.displayUserList();

list1.clearScreen();

list1.addUser();

}

}

And here is the User Class.

import java.io.Serializable;

import java.util.Vector;

/**

* Class - User

*Written to hold user details on a file

*that's encrypted (I hope)

* @author Emyr Williams

*

* version 1.0.0 - Written on 29/09/06

*

*/

publicclass Userimplements Comparable<User>, Serializable

{

public String userName;

public String userPassword;

// a check to see if the user is an administrator

publicboolean isAdministrator =false;

/*

* Constructor User

*

* Allows me to get a handle on the user.

*/

public User(String userName, String userPassword,boolean isAdministrator)

{

this.userName = userName;

this.userPassword = userPassword;

this.isAdministrator = isAdministrator;

}

public User(String userName, String userPassword)

{

this.userName = userName;

this.userPassword = userPassword;

}

/*

* The sets

*/

publicvoid setUserName(String theUserName)

{

userName = theUserName;

}

publicvoid setUserPassword(String theUserPassword)

{

userPassword = theUserPassword;

}

/*

* The gets

*/

public String getUserName()

{

return userName;

}

public String getUserPassword()

{

return userPassword;

}

publicint compareTo(User user)

{

int result = userName.compareTo(user.userName);

// TODO Auto-generated method stub

return result;

}

}

[14124 byte] By [Emyra] at [2007-10-3 8:07:07]
# 1

You are getting a ClassCastException because you are trying to cast to the wrong type. The object you wrote is a Vector<User>, so you need to read a Vector<User>. You'll only need one readObject()/writeObject() for the entire collection, which is probably good news for you.

Brian

brian@cubik.caa at 2007-7-15 3:11:05 > top of Java-index,Core,Core APIs...
# 2
Hi Brian,Thanks for getting back to me. however you'll have to explain it in a bit of a simpler way I'm afraid, as I'm a bit of a newbie at Java, I did it at university but that was three years ago, and sadly I've forgotten a fair bit since then I'm afraid.Emyr
Emyra at 2007-7-15 3:11:05 > top of Java-index,Core,Core APIs...
# 3

OK, one more try. You have this code in UserList.writeToFile():

try {

objectOut = new ObjectOutputStream(new BufferedOutputStream

(new FileOutputStream(theFile)));

objectOut.writeObject(users);

System.out.println("File written");

}

Notice that you write the users object, which is defined as type Vector<User>.

You have this in UserList.loadUserList():

user = (User)objectIn.readObject();

You read an object and attempt to cast it to type User. But look above: you wrote an object of type Vector<User> in writeToFile(). Your loadUserList() needs to read exactly the objects you wrote in writeToFile(), or you will get this ClassCastException. My comment about only requiring a single readObject()/writeObject() call was simply highlighting the fact that you can write an entire Collection to disk in one line of code. No worrying about what record is stored where; Collections manage their own serialization. That's as simple as I can explain it.

Brian

brian@cubik.caa at 2007-7-15 3:11:05 > top of Java-index,Core,Core APIs...
# 4

Hi Brian,

One more question I'm afraid....

I've tried all sorts of permutations to read in the object exactly as it is, however, I'm still unable to cast it to the proper object. I tried casting it as follows

user = (<User>)objectIn.readObject();

I know that it should be simple, however I've never done this particular element to java programming before, and I am at a total loss.

Now I know I've got that wrong, because my IDE is telline me so, however I am at a total loss as to how on earth I read the object in. I've tried all sorts of things to get it to work, however the IDE keeps telling me weird and wonderful errors, (I'm using Eclipse).

Once again, I'm sorry to inconveinience you like this.

Emyr

p.s Dollars are on their way

Message was edited by:

Emyr

Emyra at 2007-7-15 3:11:05 > top of Java-index,Core,Core APIs...
# 5

> user = (<User>)objectIn.readObject();

You're still trying to read the wrong object! Think about it: You wrote the users object in writeToFile(). That's the one declared as a Vector<User>. Therefore, you need to reassign the users object as the end result of this method. So declare another object of type Vector<User> (maybe call it temp, or some other boring name like that) and do this:

Vector<User> temp = (Vector<User>) objectIn.readObject();

users = temp

> I know that it should be simple, however I've never

> done this particular element to java programming

> before, and I am at a total loss.

I think you're still not grasping what I'm getting at: you wrote an object of type Vector<User> with writeObject(). Therefore, readObject() on the ObjectInputStream of the file created by writeObject() will return an object of type Vector<User>. However, because readObject() is declared to return type Object, you need to explicitly tell your program that the object you're reading is really a Vector<User>. Here you use knowledge that is not available to the compiler and tell your program the real type of the object. The compiler can't analyze your code and see what order objects are written and thus know the type of objects as they are read.

readObject() is a little special when you do casting. No matter how you do the casting, you will always receive a compiler warning about "Unchecked conversion to Vector<User>". The reason is that ObjectOutputStream actually only writes an object of type Vector and throws away the parameterization, presumably to avoid storing the User class unnecessarily.

Brian

brian@cubik.caa at 2007-7-15 3:11:05 > top of Java-index,Core,Core APIs...
# 6

Hi Brian.

Many thanks for the help, I typed in what you suggested, and it all made sense to me, so I've added it to me java snipet folder, so that if I get stuck again, i'll lokk it up there.

However the one problem is now I'm having an InvalidClassException, and I'm not sure why, when it first came up I added a constructor with no arguments to both classes, yet it still throws the exception.

And I'm certain that the Class ID is exactly what it's meant to be, it implements Serializable. And the code that writes the file makes the user object serializable. Perhaps I need to write the file I/O stuff in a seperate class?

From what I can gather from my code, there should be no reason for it not to be working properly. Did the code work for you?

Emyr

Emyra at 2007-7-15 3:11:05 > top of Java-index,Core,Core APIs...
# 7

Hi there,

I managed to find out what the problem was.

It turns out that I missed out this line

private static final long serialVersionUID = 1;

And now the program works fine, all that remains now is for me to write the GUI code for it. Oh happy day!!

Thanks for all your help Brian, I'd have never got this far other wise.

Emyr

Emyra at 2007-7-15 3:11:05 > top of Java-index,Core,Core APIs...