Reputation: 7551
Thanks everyone for the great assistance, here I have to add one possible reason regarding the exception:
If you add readObject()
and writeObject()
in the domain classes(like class college below) and also you have to call ObjectOutputStream.writeObject()
method in main() method, then make sure:
---Do not place ObjectOutputStream.close()
method in the domain class. It will cause exception because then it is illegal to operate on that object since it is closed(how can the program read the file or close the file after it have been already closed?).
I know it is a minor issue but quite subtle to debug as the exception will not tell anything about it. So this is a little bit of heads up for the record.
I try to implement a simple snippet to compromise serialization on transient object, which is serialize the primitive fields of that transient object, then deserialize those primitive fields by the ObjectInputStream, finally compose a new object with them. The scenario is like this:
public class College implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private transient City city; //transient
private String zipCode;
// constructors & getter/setters
private void writeObject(ObjectOutputStream os){
try {
os.defaultWriteObject();
os.writeInt(city.getCode());
os.writeInt(city.getPopulation());
os.writeObject(city.getName());
os.flush();
os.close(); // update: not good practice, may throw exception.
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void readObject(ObjectInputStream os){
try {
os.defaultReadObject();
int code = os.readInt();
int population = os.readInt();
String name = (String)os.readObject();
City theCity = new City(code, name, population);
System.out.println(theCity.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here is the City class
public class City {
// the primitive & String fields
private int code;
private String name;
private int population;
// getter/setters
}
And here is the lovely code to write and read the college
object(a little bit chunky, sorry)
public class GeneralTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
City city = new City(375, "New York", 380897);
College college = new College("NYU", city, "10289");
College readCollege = null;
City readCity = null;
System.out.println("Before serialization -- City: ["+city.toString()+"], College: ["+college.toString()+"]");
try {
FileOutputStream fs = new FileOutputStream("college.foo");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(college);
os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FileInputStream fis = new FileInputStream("college.foo");
ObjectInputStream ois = new ObjectInputStream(fis);
readCollege = (College)ois.readObject();
//get values to compose a city object
int id = ois.readInt();
int population = ois.readInt();
String name = ois.readUTF();
readCity = new City(id, name, population);
ois.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("After serialization -- City: ["+readCity.toString()+"], College: ["+readCollege.toString()+"]");
}
}
And then I got this exceptions and the readCollege
and readCity
are apparently null :(
java.io.IOException: Write error
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:282)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1847)
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1756)
at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1257)
at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1211)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1395)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:333)
at serialized.GeneralTest.main(GeneralTest.java:27)
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.readByte(ObjectInputStream.java:2721)
at java.io.ObjectInputStream$BlockDataInputStream.readUTFChar(ObjectInputStream.java:3113)
at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3010)
at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:2819)
at java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1050)
at serialized.College.readObject(College.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:969)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at serialized.GeneralTest.main(GeneralTest.java:40)
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2553)
at java.io.ObjectInputStream.skipCustomData(ObjectInputStream.java:1899)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1873)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at serialized.GeneralTest.main(GeneralTest.java:40)
Exception in thread "main" java.lang.NullPointerException
at serialized.GeneralTest.main(GeneralTest.java:52)
Any ideas? Thanks in advance.
Upvotes: 1
Views: 1501
Reputation: 82589
Here's your section of code that outputs
FileOutputStream fs = new FileOutputStream("college.foo");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(college);
os.close();
You create your stream, you write the college
object, and you close it.
Here's you're reading part:
FileInputStream fis = new FileInputStream("college.foo");
ObjectInputStream ois = new ObjectInputStream(fis);
readCollege = (College)ois.readObject();
At this point, you've already read everything you've written. You wrote college before, and now you read it.
Then you go and do this:
//get values to compose a city object
int id = ois.readInt();
int population = ois.readInt();
String name = ois.readUTF();
readCity = new City(id, name, population);
How can you expect to be reading anything here? You only wrote college
. Then you read college
back in (into the readCollege
reference. Then you're trying to read two more ints and a String? Where is that data supposed to come from? There's nothing left to read.
Upvotes: 1
Reputation: 22191
When you execute this line:
readCollege = (College)ois.readObject();
There's nothing anymore in the stream afterwards.
So your futur attempt to reading the same stream throw a logically java.io.EOFException
:
(Besides, notice the replacement of readUTF()
by readObject()
)
//get values to compose a city object
int id = ois.readInt(); // there's nothing more !! throws exception!
int zip = ois.readInt();
String name = (String)ois.readObject();
Indeed, you haven't added your custom values while writing to the stream.
So,one example of solution, add the three lines dedicated to adding elements needed for City
:
try {
FileOutputStream fs = new FileOutputStream("college.foo");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(college);
os.writeInt(1); //adding the id !
os.writeInt(75019); //adding the zip !
os.writeObject("name"); //adding the name !
os.close();
} catch (IOException e) {
e.printStackTrace();
}
Of course, order of read fields has to be the same of the one during writing.
UPDATE AFTER YOUR COMMENT:
In fact, you already read the custom values for City
within College
class through your readObject()
method, so these lines are useless:
int id = ois.readInt();
int population = ois.readInt();
String name = (String)ois.readObject(); // remove them all
Why ??? Because they merely throw the java.io.EOFException
since nothing more to read as I explained before.
Here a working global code:
class College implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private transient City city; //transient
private String zipCode;
College(String name, City city, String zipCode) {
this.name = name;
this.city = city;
this.zipCode = zipCode;
}
private void readObject(ObjectInputStream os) {
try {
os.defaultReadObject();
int code = os.readInt();
int population = os.readInt();
String name = (String) os.readObject();
this.city = new City(code, name, population);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void writeObject(ObjectOutputStream os) {
try {
os.defaultWriteObject();
os.writeInt(1);
os.writeInt(200);
os.writeObject("thename");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
}
class City {
// the primitive & String fields
private int code;
private String name;
private int population;
City(int code, String name, int population) {
this.code = code;
this.name = name;
this.population = population;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
// getter/setters
}
public class Launcher {
public static void main(String[] args) {
// TODO Auto-generated method stub
City city = new City(375, "New York", 380897);
College college = new College("NYU", city, "10289");
College readCollege = null;
City readCity = null;
System.out.println("Before serialization -- City: [" + city.toString() + "], College: [" + college.toString() + "]");
try {
FileOutputStream fs = new FileOutputStream("college.foo");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(college);
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fis = new FileInputStream("college.foo");
ObjectInputStream ois = new ObjectInputStream(fis);
readCollege = (College) ois.readObject();
readCity = readCollege.getCity();
ois.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("After serialization -- City: [" + readCity.toString() + "], College: [" + readCollege.toString() + "]");
}
}
Upvotes: 1
Reputation: 635
replace your ois.readUTF() with ois.readObject() and cast it to a String.
String name = (String) ois.readObject();
didn't compile/tried that...
Upvotes: 1