I have a custom class (constructor below) that I cannot seem to serialize.
public ObjectNode(String name, int crackLevel,ArrayList<ObjectNode> filesOnComputer)
Every time I try to serialize an object of this class from an ArrayList of object nodes I get a Class cast exception. ArrayList cannot be cast to ObjectNode
Code- Global Vars:
ArrayList<ObjectNode>a=new ArrayList<ObjectNode>();
File file = new File("/mnt/sdcard/","cheesepuff.txt");
Relevant Code:
public void serializeFile()
{
a.add(new ObjectNode("Level 1 Waterwall","ww1", 1, 5));
try {
Log.i("AAA","before serialize: "+a.toString());
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(a);
oos.flush();
oos.close();
Log.i("AAA","finished serialize");
}
catch(Exception e) {
Log.i("aaa","Exception during serialization: " + e);
System.exit(0);
}
}
public void deserializeFile()
{
try {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
ObjectNode obj=(ObjectNode)ois.readObject();
Log.i("aaa","obj: "+obj.ts());
//a.add((ObjectNode) ois.readObject());
ois.close();
Log.i("aaa","after serialize: " + a);
}
catch(Exception e) {
Log.i("aaa","Exception during deserialization: " +
e);
System.exit(0);
}
}
Is my best option to make everything a string in order to serialize that, and then convert the string back to what I actually need after deserialization?
You are serializing a which is ArrayList<ObjectNode>.
oos.writeObject(a);
When deserializing, you get back exactly that, but you try to store it as ObjectNode
ObjectNode obj=(ObjectNode)ois.readObject();
You should do
ArrayList<ObjectNode> obj = (ArrayList<ObjectNode>)ois.readObject();
UPDATE: Or, as PeterLawrey correctly states,
List<ObjectNode> obj = (List<ObjectNode>) ois.readObject;
(probably then you would have to redefine a as List<ObjectNode>, but that is another good thing to do).
You are writing an ArrayList, this means you must cast it to an ArrayList (or better, a List) when you read it.
Related
I am writing a small program that inserts customer details in ArrayList and write it in file.
The problem is with ObjectOutputStream I was able to append data in file with turning FileOutputStream("",true). But when I try to read data with ObjectInputStream it only reads data that was inserted at first instance. But data is being added to file.
Here is the code -
public void insertCustomer() throws IOException
{
Customer1=new customerDetails("1", "Moeen4", "654654", "asdf", "coding", "student", "65464", "3210");
Customer3=new customerDetails("3", "Moeen5", "888888", "asdf", "coding", "student2", "65464", "321022");
Customer4=new customerDetails("4", "Moeen6", "654654", "asdf", "coding", "student", "65464", "7890");
_list=new ArrayList<customerDetails>();
_list.add(Customer1);
_list.add(Customer3);
_list.add(Customer4);
customersList cl=new customersList();
cl.WriteObjectToFile(files._customers, _list);
ArrayList<customerDetails>li=new ArrayList<customerDetails>();
li= (ArrayList) cl.ReadObjectFromFile(files._customers);
for(int i=0;i<li.size();i++)
{ System.out.println(li.size());
System.out.println(li.get(i).Id);
System.out.println(li.get(i).name);
System.out.println(li.get(i).annual_Salary);
System.out.println(li.get(i).Company);
System.out.println(li.get(i).dateOfBirth);
System.out.println(li.get(i).phone_Number);
}
}
public void WriteObjectToFile(String filepath,Object serObj) {
try {
FileOutputStream fileOut = new FileOutputStream(filepath,true);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serObj);
objectOut.close();
System.out.println("The Object was succesfully written to a file");
} catch (Exception ex) {
ex.printStackTrace();
}
}
public Object ReadObjectFromFile(String filepath) {
try {
FileInputStream fileIn = new FileInputStream(filepath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
Object obj = objectIn.readObject();
objectIn.close();
System.out.println("The Object has been read from the file");
return obj;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
The real problem here is this:
FileOutputStream fileOut = new FileOutputStream(filepath, true);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serObj);
You cannot append to an existing serialization like this. If you do get an exception when attempting to read any objects appended to a pre-existing (non-empty) file.
There is a trick / hack that allows you to append objects though; see Appending to an ObjectOutputStream. (The trick involves suppressing the writing of the object stream header. It is most easily done by overriding the method that does this.)
The other approach is to keep the ObjectOutputStream open between writeObject calls. However there are use-cases where that won't be possible.
Note that there is a semantic difference between these two approaches. The best way to explain it is that the first one behaves as if you called reset() each time you write an object; see the javadoc.
Another thing to note about your example is that your reader code only reads one object. If you want to read multiple objects, you need to call readObject in a loop. And that will only work if you have used the trick / hack above to avoid writing a spurious header.
As suggested the code is only reading the first object and you would need to use a loop to read all the objects from multiple writes.
However -
If you change the above code i.e. ReadObjectFromFile to use a loop this will lead to an StreamCorruptedException: invalid type code: AC. The ObjectOutputStream constructor writes a serialization stream header to the OutputStream i.e. the file, when it is closed and reopend using new ObjectOutputStream and new FileOutputStream(filepath, true) a new header will be written at the append point so you will get an exception as the header is only expected once at the beginning of the file
This will need to be handled e.g.
Use the same ObjectOutputStream for the duration
Override java.io.ObjectOutputStream.writeStreamHeader() to account for append to a file
Change the approach and use List<List<Object>> which you could read, add, write to as a whole.
Loop example would throw exception unless ObjectOutputStream approach is changed
public Object ReadObjectFromFile(String filepath) {
List<List<Object>> objects = new ArrayList<>();
FileInputStream fileIn = new FileInputStream(filepath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
try {
while (true) {
List<Object> obj = (List<Object>) objectIn.readObject();
// This will throw StreamCorruptedException: invalid type code: AC
objects.add(obj);
System.out.println("The Object has been read from the file");
}
} catch (EOFException ex) {
// ENDS WHEN ALL READ
} finally {
fileIn.close();
objectIn.close();
}
return objects;
}
Sudo code List<List<Object>> approach -
public void readAndWrite() {
List<Object> customer = List.of(new CustomerDetails(...),
new CustomerDetails(...),
new CustomerDetails(...));
List<List<Object>> objects = readFromFile("existing-customer-file.txt");
objects.addAll(customer);
writeObjectToFile(objects);
}
Is it possible to change the object type of an array list i.e. from an Object ArrayList to a specific object ArrayList. I have tried using a for each. Alternatively is there a way to change the filehandling method such that it can return a specific type depending on which file it reads from without duplicating code?
My Attempt:
ArrayList<Object> librarianList = FileHandling.getLibrarianRecords(fileName);
ArrayList<Librarian> libList = new ArrayList<>();
for (Object addType: librarianList) {
libList.add(addType);
}
getLibrarianRecords code
public static ArrayList<Object> getLibrarianRecords(String filename){
ArrayList<Object> fromFile = new ArrayList<>(); //Array of
// existing librarians
try{
FileInputStream fIS =
new FileInputStream(SYSTEM_PATH + filename);
ObjectInputStream oIS = new ObjectInputStream(fIS);
fromFile = (ArrayList<Object>)oIS.readObject();
} catch (IOException ex){
System.out.println("Failed to read from file " + ex.getMessage());
ex.printStackTrace(); //Catches an IO exception.
} catch (ClassNotFoundException ex){
System.out.println("Error class not found" + ex.getMessage());
ex.printStackTrace(); //Catches a class not found
// exception.
}
return fromFile; //Returns the array list.
}
It is rarely a good idea to read objects from a file like this. That said all you really need to do is to cast the result of oIS.readObject() to an ArrayList<Librarian> instead of carrying it to ArrayList<Object> (as you do now) and then amend the return type of getLibrarianRecords. Oh, and naturally also the type of the local variable fromFile.
public static ArrayList<Librarian> getLibrarianRecords(String filename){
ArrayList<Librarian> fromFile = new ArrayList<>(); //Array of
// existing librarians
try{
FileInputStream fIS =
new FileInputStream(SYSTEM_PATH + filename);
ObjectInputStream oIS = new ObjectInputStream(fIS);
fromFile = (ArrayList<Librarian>)oIS.readObject();
} catch (IOException ex){
System.out.println("Failed to read from file " + ex.getMessage());
ex.printStackTrace(); //Catches an IO exception.
} catch (ClassNotFoundException ex){
System.out.println("Error class not found" + ex.getMessage());
ex.printStackTrace(); //Catches a class not found
// exception.
}
return fromFile; //Returns the array list.
}
There should then be no need to loop over the list to actually do the type conversion on an element by element basis.
Thanks to #user3170251 for suggesting casting
ArrayList<Object> librarianList = FileHandling.getLibrarianRecords(fileName);
ArrayList<Librarian> libList = new ArrayList<>();
for (Object addType: librarianList) {
libList.add((Librarian) addType);
}
For changing the type this does work.
You can use this generic class definition
class ArrayListConverter<T> {
List<T> cast;
public ArrayListConverter(List<T> typeList){
cast = new ArrayList<>();
for (Object addType: typeList) {
cast.add((T)addType);
}
}
public List<T> getList(){
return cast;
}
}
Just do this:
ArrayListConverter<Librarian> conv = new ArrayListConverter<>(libList);
ArrayList<Librarian> libListOg = conv.getList();
i am having a little trouble reading a object from a text file as it preduces the following error;
Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to stock.control.system.StockItem
which is this line;
StockItem result = (StockItem) ois.readObject();
below is how i save my file;
try { FileOutputStream fout = new FileOutputStream(filename);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(StockItems); }
catch (java.io.FileNotFoundException error) {
System.out.println("FILE NOT FOUND!");
}
and here is what i have done for far for loading the file back into a object ArrayList;
try {
FileInputStream fis = new FileInputStream(filename);
ObjectInputStream ois = new ObjectInputStream(fis);
System.out.println("LOADING DATA ...");
StockItem result = (StockItem) ois.readObject();
ois.close();
System.out.println(result.getItemID() + ", " + result.getItemDesc()
+ ", " + result.getPrice() + ", " + result.getQuantity() + ", "
+ result.getReOrderLevel()); // used for testing
} catch (java.io.FileNotFoundException error) {
System.out.println("FILE NOT FOUND!");
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(StockArrayList.class.getName()).log(Level.SEVERE, null, ex);
}
if anywhere could educate me so it can be done correctly it would be much appreciated.
The error says that what was written to the file is an ArrayList.
Looks like that StockItems you write is ArrayList<StockItem>. When you read, you get the array list back, so you can't cast it to StockItem. You need to cast it to ArrayList and then iterate over the list and cast each element to StockItem.
Looks like the file does not contain what you think it does. It contains an ArrayList, not a StockItem. Try taking the first element of the arraylist:
StockItem result = (StockItem) ((ArrayList)ois.readObject()).get(0)
and see what type that is.
I just had to assign the output to a array list in a tester class which was then in turn fed into a interface and from within the interface i had to assign it into another array list, this was how i fixed this error.
I wrote this function which will attempt to store the map but its not working I think? I am using netbeans and each time i go to the directory of project in the java src i can't find the created file or anywhere else in the project. The map is surely valid because output comes out perfect when am not dealing with storage. btw I do implement seriliazable :)
Note: the map is of type TreeMap
public boolean storeMap(TreeMap<DateTime, Integer> map){
try{
f_out = new FileOutputStream("mapObject.data");
obj_out = new ObjectOutputStream (f_out);
obj_out.writeObject(map);
return true;
}catch(IOException ioe){
System.err.print(ioe);
return false;
}
}
is there a reason why the output file is not generated?
Thanks
I suggest to use absolute path, that is something like
f_out = new FileOutputStream("/home/username/mapObject.data");
or on windows
f_out = new FileOutputStream("c:\\work\\mapObject.data");
If there was no exception thrown (System.err.print(ioe); this line did not print anything) then the file was created somewhere.
SERIALIZE A HASHMAP:
This code is working fine , I have implemented and used in my app. Plz make ur functions accordingly for saving map and retrieving map.
Imp thing is, you need to make confirm that the objects you are putting as value in map must be serializable , means they should implement serailizbele interface. ex.
Map<.String,String> hashmap=new HashMap<.String,String>().. here in this line ...map and string both are implictly serializable , so we dont need to implement serializble for these explicitly but if you put your own object that must be serializable.
public static void main(String arr[])
{
Map<String,String> hashmap=new HashMap<String,String>();
hashmap.put("key1","value1");
hashmap.put("key2","value2");
hashmap.put("key3","value3");
hashmap.put("key4","value4");
FileOutputStream fos;
try {
fos = new FileOutputStream("c://list.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(hashmap);
oos.close();
FileInputStream fis = new FileInputStream("c://list.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Map<String,String> anotherList = (Map<String,String>) ois.readObject();
ois.close();
System.out.println(anotherList);
} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
} catch (ClassNotFoundException e) {e.printStackTrace();
}
}
Try to call fulsh() method for outputStreams.
obj_out.flush();
f_out.flush();
and close them in finally statment.
I have created a method in my java assignment to write into a file from a LinkedList (I used serialization) , then I have created another method to read the file into the inkedList. The following is my method's body:
try {
FileInputStream fin = new FileInputStream("c:\\Info.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
Employee e = (Employee) ois.readObject();
linkP.add(e);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
but it doesnt work right. I think this part:
Employee e = (Employee) ois.readObject();
linkP.add(e);
reads only the first object of the file into the linkedlist and ignores other objects. I surrounded it for loop and while loop several times but it causes EOFException. How can I change my method to read all of the file's objects into the LinkedList?
If you used LinkedList for serialization you should expect a LinkedList to deserialize:
linkP= (LinkedList) ois.readObject();
instead of
Employee e = (Employee) ois.readObject();
linkP.add(e);
The easiest way is to include the size of the list as the first thing written to the file. When you read the file, the first thing you retrieve is the size. Then you can read the expected number of objects.
Are you sure that the serialized file contains all of the elements? It looks to me like you might only be serializing one.
Note: Please also add the code where you create the info.ser file, since you may have corrupted the ObjectOutputStream by closing/reopening it for each object.
But to answer your question, the proper way of doing it (without catching exceptions) would be:
#Test
public void testSerializingListByEntries() throws Exception {
List<Serializable> list = new ArrayList<Serializable>();
list.add(new Date());
list.add(new Date());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeInt(list.size()); // Magic
for(Serializable o : list) {
oos.writeObject(o);
}
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
int count = ois.readInt();
List<Object> newList = new ArrayList<Object>();
for(int i = 0; i < count;i++) {
newList.add(ois.readObject());
}
ois.close();
assertEquals(list,newList);
}
Yes, you need to close the streams yourself of course. Omitted for readability.
Would probably need to see how you're writing in the first place but generally:
ObjectInputStream is = null;
try
{
is = new ObjectInputStream(new FileInputStream("c:/Info.ser"));
Object object = null;
while ((object = is.readObject()) != null)
{
linkP.add(object);
}
}
catch(Exception e)
{
//Whatever you need to do
}
finally
{
//Never forget to close your streams or you'll run into memory leaks
try
{
if (is != null)
{
is.close();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
Also, its probably better practice for you to handle the exceptions individually but I can't really tell what the streams throw so replace the (Exception e) with everything else.
surround Employee e = (Employee) ois.readObject();
linkP.add(e);
with a for loop as you suggested and surround the .readObject call with a try/catc(EOFException)
Just catch EOFException separately inside your reading loop and process it accordingly, i.e. break out of the loop.