This is a followup to Serializing a vector
I'm trying to implement loading and saving for a game I'm working on.
I want to save a Maze which contains, among other attributes, an ArrayList of Entity.
Entity is a super class for Dragon, Hero and Item. All three of these types can be contained at once in the vector.
Using the "automatic" serialization mechanism (adding implements Serializable to Maze) saves all attributes but the ArrayList.
Why does this happen?
My code is below, for completeness' sake.
package logic;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public final class LoadAndSave {
public static final transient boolean available = false;
public static final boolean serialize(Object obj) {
// Write to disk with FileOutputStream
FileOutputStream saveFile;
try {
saveFile = new FileOutputStream("game.sav");
} catch (FileNotFoundException e) {
return false;
}
// Write object with ObjectOutputStream
ObjectOutputStream objOut;
try {
objOut = new ObjectOutputStream(saveFile);
} catch (IOException e) {
//
return false;
}
// Write object out to disk
try {
objOut.writeObject(obj);
} catch (IOException e) {
return false;
}
return true;
}
public static final Object load() {
FileInputStream fileIn;
try {
fileIn = new FileInputStream("game.sav");
} catch (FileNotFoundException e1) {
return null;
}
// Read object using ObjectInputStream
ObjectInputStream objIn;
try {
objIn = new ObjectInputStream(fileIn);
} catch (IOException e) {
return null;
}
// Read an object
Object obj;
try {
obj = objIn.readObject();
} catch (IOException e) {
return null;
} catch (ClassNotFoundException e) {
return null;
}
return obj;
}
}
Is Entity serializable too? (you mentioned that just Maze is serializable).
And be sure that the list is not defined as transient or static, otherwise it will be skipped by the serialization mechanism.
I checked Your code with the following assumptions:
class Entity implements Serializable {}
and:
private char[][] mazeWalls = new char[0][0];
private Vector<Entity> entities = new Vector<Entity>();
...and it works perfectly, serializing and deserializing empty Entity objects...
You need to make sure that you close your streams. Your code for load() can be simplified to look something like this:
ObjectInputStream objIn = null;
try {
objIn = new ObjectInputStream(new FileInputStream("game.sav"));
return objIn.readObject();
} catch (Exception exception) {
// Deal with errors
return null;
} finally {
if (objIn != null) {
try {
objIn.close();
} catch (Exception exception) {}
}
}
serialise() can be altered in a similar way.
Related
I'm trying to implement object serialization in java. I'm not sure why my code is currently leading to an EOFException, as my code is writing to the file it's supposed to:
Currently, my code is:
import java.io.*;
public class main {
public static void main(String[] args) {
product p1 = new product("product", 0, "this is a product.");
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("info.dat")));
out.writeObject(p1);
out.writeObject(p1);
System.out.println("Wrote to file");
} catch (FileNotFoundException e) {
System.out.println("");
} catch (IOException e) {
System.out.println("");
}
ObjectInputStream in = null;
try {
in = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream("info.dat")));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
while product class is extremely simple, being only:
import java.io.Serializable;
public class product implements Serializable {
String name;
double cost;
String description;
public product(String a,double b,String c) {
name = a;
cost = b;
description = c;
}
}
Currently, the output is
Meaning that my code did run and did write to file. I also added an extra write object just in case, so I really don't understand how an EOF error is occurring. Can somebody please explain why?
I'm trying to serialize a simple class Sertest. It has one member Decision which itself has only a boolean and an int member, both classes implement Serializable.
However I get a java.io.NotSerializableException: Decision.
Decision.java:
import java.io.Serializable;
public class Decision implements Serializable {
public final int chosenValue;
public final boolean continuePlaying;
public Decision(int chosenValue, boolean continuePlaying){
this.chosenValue = chosenValue;
this.continuePlaying = continuePlaying;
}
}
Sertest.java:
import java.io.Serializable;
public class Sertest implements Serializable {
private Decision test;
public Sertest(){
this.test = new Decision(1, true);
}
public Decision getTest(){
return test;
}
}
And finally, my Main.java code:
Sertest s = null;
File f = new File("sertest.asdf");
if(f.exists()){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(f));
s = (Sertest) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
else{
s = new Sertest();
ObjectOutputStream oos = null;
try{
oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
if (s != null)
System.out.println(s.getTest().chosenValue);
I searched and searched StackOverflow and Duckduckgo, but just can't find the reason for this. I tried:
Refactoring the Decision class to have private members with getter methods
Adding a noarg-constructor to Decision
Debugging by setting a breakpoint in ObjectInputStream.defaultReadFields(ObjectInputStream.java:2355) (However this didn't work)
something is really messed up. I've got a ".ser" document in the assets folder, which stores an ArrayList of Objetcs. In an android application, I want to read this objects. There are a lot of posts related to this issue, however none of them could solve my problem. The strange part is, when I am using similar code in non - android context / "normal" java, it works properly. Here, the last line throws a NullPointerException - What is going wrong?
public void getData() {
ArrayList<MyClass> output= null;
InputStream is = null;
ObjectInputStream ois = null;
try{
is = this.getAssets().open("data.ser");
ois = new ObjectInputStream(is);
output = (ArrayList<MyClass>)ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Log.d("TAG", output.get(0).getId());
}
I would create a class and place the array within a single object:
public class ListObjects implements Serializable {
List<MyClass> listMyClass = new ArrayList<>();
public ListObjects(){
}
public List<MyClass> getListMyClass() {
return listMyClass;
}
public void setListMyClass(List<MyClass> listMyClass) {
this.listMyClass = listMyClass;
}
}
I had a similar problem. And it was because the name of the package in the java app was not called the same as the package name in android. And therefore I did not recognize them as equal objects. This is how I do it:
public static Object fromData(byte[] data) {
ObjectInputStream ois = null;
Object object = null;
try {
ois = new ObjectInputStream(
new ByteArrayInputStream(data));
object = ois.readObject();
} catch (Exception ex) {
Logger.getLogger(ModeloApp.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
ois.close();
} catch (Exception ex) {
Logger.getLogger(ModeloApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
return object;
}
I'm a student practicing my File IO skills and I am coming up against a problem with reading Objects from a file using ObjectInputStream. The code is consistently throwing an InvalidClassException and I can't find how the code is throwing it online or by trial and error. Here's my code:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class ReadFromFile {
String filename;
List<Object> os;
public ReadFromFile(String filename) {
this.filename = filename;
os = new ArrayList<>();
}
public Object[] readObject() {
try {
FileInputStream fis = new FileInputStream(filename);
ObjectInputStream ois = new ObjectInputStream(fis);
System.out.print("reading\n");
while (true) {
os.add(ois.readObject());
System.out.print("read one\n");
}
} catch (EOFException e) {
return os.toArray();
} catch (FileNotFoundException e) {
System.out.print("File not found\n");
return os.toArray();
} catch (ClassNotFoundException e) {
System.out.print("Class not found\n");
return os.toArray();
} catch (StreamCorruptedException e) {
System.out.print("SC Exception\n");
e.printStackTrace();
return os.toArray();
} catch (InvalidClassException e) {
e.printStackTrace();
System.out.print("IC Exception\n");
return os.toArray();
} catch (OptionalDataException e) {
System.out.print("OD Exception\n");
return os.toArray();
} catch (IOException e) {
System.out.print("IO Exception\n");
return os.toArray();
}
}
}
I wrote all of the separate catch blocks to figure out what Exception was being thrown and it always throws the InvalidClassException.
Here also is my Tree Class:
import java.io.Serializable;
public class Tree implements Serializable {
private static final long serialVersionUID = -310842754445106856L;
String species;
int age;
double radius;
public Tree() {
this.species = null;
this.age = 0;
this.radius = 0;
}
public Tree(String species, int age, double radius) {
this.species = species;
this.age = age;
this.radius = radius;
}
public String toString() {
return species + ", age: " + age + ", radius: " + radius;
}
}
And here is my write to file function:
public boolean write(Object object) {
try {
File f = new File(filename);
FileOutputStream fos = new FileOutputStream(f,true);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object + "\n");
oos.close();
} catch (FileNotFoundException e) {
System.out.print("File Not Found\n");
return false;
} catch (IOException e) {
System.out.print("IOException\n");
return false;
}
return true;
}
Your knowledge is appreciated...
Stack trace:
SC Exception
java.io.StreamCorruptedException: invalid stream header: 0AACED00
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:806)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at ReadFromFile.readObject(ReadFromFile.java:17)
at WriteAndRecord.main(WriteAndRecord.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Process finished with exit code 0
java.io.StreamCorruptedException: invalid stream header: 0AACED00
This is caused by appending to the FileOutputStream. As I mentioned in a comment above, you can't append to a stream written by ObjectOutputStream, at least not without special measures. Keep the file and the ObjectOutputStream open until you've written all the objects you want to write, then close it, then deserialize from it.
NB As I also mentioned,
while ((object = in.readObect()) != null)
is not a valid object-reading loop. readObject() doesn't return null at end of stream: it throws EOFException. null can occur anywhere in the stream, any time you write one. The correct form of the loop is:
try
{
for (;;)
{
Object object = in.readObject();
// ...
}
}
catch (EOFException exc)
{
// end of stream
}
// other catch blocks ...
NB 2 This:
oos.writeObject(object + "\n");
should be just
oos.writeObject(object);
Otherwise you're implicity calling toString() and pointlessly appending a line terminator, so the result of readObject() will be a String, not the original object.
I think this was caused by the lack of a serialVersionUID.
Whenever you serialize an object, the ClassLoader needs something to verify the new loaded object against to verify it and ensure its compatibility. In order to do this, you just need to define a field in your class like this:
private static final long serialVersionUID = 12358903454875L;
Your IDE may have also given you a warning stating the lack of it (Eclipse does this).
This should solve your problem.
You can learn more in this excellent answer by Jon Skeet here: What is a serialVersionUID and why should I use it?.
Here's my current code:
//export method
public static void exportObj (Object obj, String fname) {
try {
// Serialize data object to a file
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fname));
out.writeObject(obj);
out.close();
} catch (IOException e) {}
}
//import method
public static Object importObj (String fname) {
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fname));
return in.readObject();
} catch (IOException e) {}
return new Object();
}
The export function works fine, I think, it turns my User object into a file and saves it, but then when I try to import it, it gives me a ClassNotFound Exception. What is happening?
All the classes you want to deserialize must exist on the CLASSPATH of the project that contains the import code.