Java Serialization - java

I'm learning now how to do serialization using Java Language. I have read some posts and docs about the subject and I tried to do a simple example (below)
public class SterializeObject implements java.io.Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private transient int code;
public SterializeObject (String n, int c){
name = n;
code = c;
}
public void printAtributes (){
System.out.println("name: " + name + "; code: " + code);
}
}
public class MainClass {
public static void main(String[] agrs) {
SterializeObject ob1 = new SterializeObject("ana", 1);
SterializeObject ob2 = new SterializeObject("rita", 2);
try {
FileOutputStream fileOut = new FileOutputStream("file.data");
ObjectOutputStream outObj = new ObjectOutputStream(fileOut);
outObj.writeObject(ob1);
outObj.writeObject(ob2);
outObj.close();
System.out.println("Objects were serialized!");
} catch (IOException e) {
e.printStackTrace();
}
ArrayList<SterializeObject> list = new ArrayList<SterializeObject>();
try {
FileInputStream fileInput = new FileInputStream("file.data");
ObjectInputStream inputObj = new ObjectInputStream(fileInput);
Object o;
try {
while ((o = inputObj.readObject()) != null) {
list.add((SterializeObject) o);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Erro foi aqui! (1)");
}
inputObj.close();
fileInput.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Erro foi aqui! (2)");
}
for (int i = 0; i < list.size(); ++i) {
list.get(i).printAtributes();
}
}
}
I created a Class SterializeObject that implements java.io.Serializable with two variables: one string (name) and one int (code) that is transient. Then In the main I generate two instances of that class and I tried to write it in a file, that I have done successfully! After that, I try to read the two object with a Loop.. there is my problem.. since the ObjectInputStream dosen't have some kind of method to see if we are in the end or not. So, I tried to do with this condition: (o = inputObj.readObject()) != null.
My output is this:
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at MainClass.main(MainClass.java:30)
Objects were serialized!
Erro foi aqui! (2)
name: ana; code: 0
name: rita; code: 0
I get the objects, but I get an error because, I think, is trying to access to something that doesn't exist.
Someone can tell me other way to do it?
Best Regards.

Read as many objects as the number of written objects, or write the list of objects itself, instead of writing every object one after the other.
(Or rely on the EOFException to detect the end of the stream, but this is ugly).

As many of you told me to do, I created a ArrayList and serialized the ArrayList.
My code is:
public class MainClass {
public static void main(String[] agrs) {
SterializeObject ob1 = new SterializeObject("ana", 1);
SterializeObject ob2 = new SterializeObject("rita", 2);
ArrayList <SterializeObject> list = new ArrayList<>();
list.add(ob1);
list.add(ob2);
ArrayList <SterializeObject> input = new ArrayList<SterializeObject>();
try {
FileOutputStream fileOut = new FileOutputStream("file.data");
ObjectOutputStream outObj = new ObjectOutputStream(fileOut);
outObj.writeObject(list);
outObj.close();
System.out.println("Objects were serialized!");
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fileInput = new FileInputStream("file.data");
ObjectInputStream inputObj = new ObjectInputStream(fileInput);
Object o;
try {
input = (ArrayList<SterializeObject>) inputObj.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Erro foi aqui! (1)");
}
inputObj.close();
fileInput.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Erro foi aqui! (2)");
}
for (int i = 0; i < input.size(); ++i) {
input.get(i).printAtributes();
}
}
}
And the output is:
Objects were serialized!
name: ana; code: 0
name: rita; code: 0
Thank you for the help!

Close the FileOutputStream also along with ObjectOutputStream
fileOut.close();

Why don't you add both object to an ArrayList, and serialize the ArrayList. Then you just have to Deserialize the ArrayList and it will be populated with both objects.

You can do this by placing the readObject call inside a try-catch block and catching that EOFException you get, signaling you have read all the objects.

Replace your while loop with this piece of code
do{
try
{
o = inputObj.readObject();
list.add((SterializeObject) o);
}
catch(EOFException e)
{
o = null;
}
}while (o != null);

Related

Reading objects from a file and adding them to an array

I'm trying to read objects from a file then add them to an Array List of Ticket. But it's not working. May I please know where's the problem?
public void writeTicketToFile(Ticket ticket) {
try {
FileOutputStream fileOut = new FileOutputStream("tickets.txt");
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(ticket.toString());
objectOut.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void readTicketFromFile(){
ArrayList<Ticket> tickets = new ArrayList<Ticket>();
try {
FileInputStream fi = new FileInputStream(new File("tickets.txt"));
ObjectInputStream oi = new ObjectInputStream(fi);
Ticket ticket;
while (ticket=oi.readObject() != null){
tickets.add((Ticket)oi.readObject());
}
System.out.println(tickets);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
One of your main problems lies here:
while (ticket=oi.readObject() != null){
tickets.add((Ticket)oi.readObject());
}
Compare the fact that you're trying to read a Ticket object out of a file with the way you're writing the Ticket to the file:
objectOut.writeObject(ticket.toString());
As you can see, you're converting the Ticket to a String and writing the String to the file. Then when you try to read, you're trying to read a Ticket. Instead, you should read a String, and then convert the String into a Ticket in code.
If Ticket is serializable, you may instead just be able to remove .toString() from the write step, but I've never worked with object streams, so I can't say 100% if that will work.
There are a lot of issues here:
Make sure your Ticket implements Serializable interface for writing/reading objects from/to file as in this simple example:
public class Ticket implements Serializable{
private String name;
private LocalDateTime issued;
public Ticket() {
}
public Ticket(String name, LocalDateTime issued) {
this.name = name;
this.issued = issued;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* #return the issued
*/
public LocalDateTime getIssued() {
return issued;
}
/**
* #param issued the issued to set
*/
public void setIssued(LocalDateTime issued) {
this.issued = issued;
}
}
Now pay attention to while writing tickets to a file to write them one at a time. You can achieve it by iterating thru your list of tickets and writing it one at a time, something like:
for (int i = 0; i < tickets.size(); i++) {
objectOut.writeObject(tickets.get(i));
}
Also, make sure to close your ObjectInputStream after reading as it will surely throw EOFException at the end, take a look at implementation of it in readTicketFromFile method.
public class SerializationAndDeserializationOfTicket {
public static void main(String[] args) {
List<Ticket> listOfTickets = new ArrayList<>();
listOfTickets.add(new Ticket("Concert 1", LocalDateTime.now()));
listOfTickets.add(new Ticket("Concert 2", LocalDateTime.now()));
listOfTickets.add(new Ticket("Concert 3", LocalDateTime.now()));
writeTicketToFile(listOfTickets);
readTicketFromFile();
}
public static void writeTicketToFile(List<Ticket> tickets) {
try {
FileOutputStream fileOut = new FileOutputStream("tickets.txt");
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
for (int i = 0; i < tickets.size(); i++) {
objectOut.writeObject(tickets.get(i));
}
objectOut.close();
} catch (IOException e) {
System.err.println("JVM reported an IO exception. Please, take a look.");
}
}
public static void readTicketFromFile() {
ArrayList<Ticket> tickets = new ArrayList<>();
try {
FileInputStream fi = new FileInputStream(new File("tickets.txt"));
ObjectInputStream oi = new ObjectInputStream(fi);
while (true) {
try {
Ticket ticket = (Ticket) oi.readObject();
tickets.add(ticket);
System.out.println(ticket.getName() + " " + ticket.getIssued());
} catch (EOFException ex) {
oi.close();
break;
}
}
} catch (IOException | ClassNotFoundException e) {
System.err.println("JVM reported an IO/ClassNotFound exception. Please, take a look.");
}
}
Just add the Ticket objects into an ArrayList and write the list (instead of each object one by one) as a single object. Then read the list from the file in your readTicketFromFile() method as :
ArrayList<Ticket> ticketsList = (ArrayList<Ticket>)oi.readObject();

Java InputStream with different Object Classes

my code has to read in two different Object Types (Bestellung, AKunde) through a ObjectOutputStream and save it in a csv file, which works.
But when i try to read them from the file it doesn't work.
Here is the code:
OutputStream:
LinkedList<Bestellung> bestellListe = verwaltungBestell.getBestellListe();
try {
fileOutputStream = new FileOutputStream(file);
outputStream = new ObjectOutputStream(fileOutputStream);
for (AKunde kunde : kundenliste) {
outputStream.writeObject(kunde);
}
for (Bestellung bestellung : bestellListe) {
outputStream.writeObject(bestellung);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
InputStream:
ArrayList<AKunde> kundenImport = new ArrayList<AKunde>();
ArrayList<Bestellung> bestellungenImport = new ArrayList<Bestellung>();
boolean cont = true;
try {
ObjectInputStream objectStream = new ObjectInputStream(new FileInputStream(directorie));
while (cont) {
AKunde kunde = null;
try {
kunde = (AKunde) objectStream.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (kunde != null) {
kundenImport.add(kunde);
} else {
cont = false;
}
}
while (cont) {
Bestellung bestellung = null;
try {
bestellung = (Bestellung) objectStream.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (bestellung != null) {
bestellungenImport.add(bestellung);
} else {
cont = false;
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
}
But it won't read the "Bestellungen" and won't save them into "bestellungenImport".
Anyone has a solution???
Your code never reaches the Bestellung reader part.
You have a false assumption that kunde =(AKunde)objectStream.readObject(); returns null.
Instead, it throws exception.
Oneway you can do is cast it like #luk2302.
Another way is to add a object count when writing your object stream:
outputStream.writeInt(kundenliste.size());
for (AKunde kunde : kundenliste) {
outputStream.writeObject(kunde);
}
outputStream.writeInt(bestellListe.size());
for (Bestellung bestellung : bestellListe) {
outputStream.writeObject(bestellung);
}
Then replace your while(cont) loop with a for each loop:
int kundeCount = objectStream.readInt();
for (int i = 0; i < kundeCount; i++) {
// Read and import kunde
}
You need to change your logic for reading objects. There are two main issues:
you never reset cont so the second while loop will never do anything
even if you did that you would always skip the first Bestellung since it was already read when the second loop is reached
I would propose something along the lines of:
Object object = objectStream.readObject();
if (object instanceof AKunde) {
kundenImport.add((AKunde) object);
} else if (object instanceof Bestellung) {
bestellungenImport.add((Bestellung) object);
} else {
// something else was read
}
You simply need to loop over this code and add proper error handling where needed.
I would suggest, you change the way you write your objects to ObjectOutputStream in the first place:
Directly write the kundenListe and bestellListe objects, so you dont't have to worry about types or number of elements when reading the objects again. Your stream of object then always contains two objects, the two lists.
// use try-with-resources if you're on Java 7 or newer
try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file))) {
// write the complete list of objects
outputStream.writeObject(kundenliste);
outputStream.writeObject(bestellListe);
} catch (IOException e) {
e.printStackTrace(); //TODO proper exception handling
}
Then you could read it just like that:
ArrayList<AKunde> kundenImport = new ArrayList<>();
ArrayList<Bestellung> bestellungenImport = new ArrayList<>();
//again try-with-resources
try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file))) {
kundenImport.addAll((List) inputStream.readObject());
bestellungenImport.addAll((List) inputStream.readObject());
} catch (IOException | ClassNotFoundException e) { //multi-catch, if Java 7 or newer
e.printStackTrace(); //TODO proper exception handling
}
Further reads:
The try-with-resources Statement
Catching Multiple Exception Types (...)

Using parsed input from text file as parameter for new Event

I've working on an assignment that asks me to alter a method in a class to take content from a textfile and use it to create multiple instances of various subclasses of the Event Class. Here is the text file:
Event=ThermostatNight,time=0
Event=LightOn,time=2000
Event=WaterOff,time=8000
Event=ThermostatDay,time=10000
Event=Bell,time=9000
Event=WaterOn,time=6000
Event=LightOff,time=4000
Event=Terminate,time=12000
The Event=* is the name of the subclass, while time=* is a parameter that is used in the subclass' constructor. The Event class itself is an abstract class and is used for inheritance.
public class Restart extends Event {
Class eventClass;
String eventInput;
Long timeDelay;
public Restart(long delayTime, String filename) {
super(delayTime);
eventsFile = filename;
}
public void action() {
List<String> examples = Arrays.asList("examples1.txt", "examples2.txt", "examples3.txt", "examples4.txt");
for (String example : examples) {
//finding pattern using Regex
Pattern pattern = Pattern.compile(example);
Matcher matcher1 = pattern.matcher(eventsFile);
if (matcher1.find()) {
File file = new File(example);
String line;
try {
FileReader fileReader = new FileReader(file);
Scanner sc = new Scanner(file);
BufferedReader bufferedReader =
new BufferedReader(fileReader);
while ((line = bufferedReader.readLine()) != null) {
sc.useDelimiter("\n");
//Parsing through text
while (sc.hasNext()) {
String s = sc.next();
String[] array1 = s.split(",");
String[] array2 = array1[0].split("=");
eventInput = array2[1];
String[] array3 = array1[1].split("=");
String timeInput = array3[1];
try {
eventClass = Class.forName(eventInput);
timeDelay = Long.parseLong(timeInput);
try {
addEvent(new eventClass(timeDelay));
}
//catch block
catch(NoSuchMethodException e){
System.out.println("No Such Method Error");
} catch (Exception e) {
System.out.println("error");
}
//catch block
} catch (ClassNotFoundException ex) {
System.out.println("Unable to locate Class");
} catch (IllegalAccessException ex) {
System.out.println("Illegal Acces Exception");
} catch (InstantiationException ex) {
System.out.println("Instantiation Exception");
}
}
}
//Close bufferedReader
bufferedReader.close();
}
//catch block
catch (FileNotFoundException ex) {
System.out.println(
"Unable to open file '" +
file + "'");
} catch (IOException ex) {
ex.printStackTrace();
}
break;
}
//if input match is not found
else {
System.out.println("No Match Found");}
}
}
I seem to be able to parse fine, and find the strings i'm looking for, but I'm not able to use eventInput which I've pulled from the text file as a parameter to create a new event.
eventClass = Class.forName(eventInput);
doesn't seem to be turning my string into an acceptable parameter either.
Any help would be much appreciated!
I know I'm probably missing something key here, but I've been staring at it too long that it seems like a lost cause.
Here is the Event class:
public abstract class Event {
private long eventTime;
protected final long delayTime;
public Event(long delayTime) {
this.delayTime = delayTime;
start();
}
public void start() { // Allows restarting
eventTime = System.currentTimeMillis() + delayTime;
}
public boolean ready() {
return System.currentTimeMillis() >= eventTime;
}
public abstract void action();
} ///:~
I think you've misunderstood how reflection works. Once you have a Class object (the output from Class.forName(), you have to find the appropriate constructor with
Constructor<T> constructor = eventClass.getConstructor(parameter types)
and then create a new instance with
constructor.newInstance(parameters);
For a no-arg constructor there's a shortcut
eventClass.newInstance();
I strongly suggest you read the tutorials on reflection before proceeding.

Read multiple different objects in a text file - Java

I'm working on a school project which consist in creating race-tournaments
I'm having an issue right now because I have multiple races-type (CarRace/BikeRace) which have Race as a parent
I'm saving an array of races no matter the specific type.
And now I need to load this list of races
public static ArrayList<Course> loadLRace(String name) {
File inFile = new File(name+".txt");
FileInputStream inFileStream;
ArrayList<Race> lRace = new ArrayList<Race>();
try {
inFileStream = new FileInputStream(inFile);
ObjectInputStream inObjectStream = new ObjectInputStream(inFileStream);
int length = inObjectStream.readInt();
for(int i = 0; i < length; i++) {
Race race = (Race)inObjectStream.readObject();
lRace.add(Race);
}
inObjectStream.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return lRace;
}
And I'm having a "non valid constructor" error, I guess this is because I don't deal with CarRace AND BikeRace separately, but how can I ?

Deserialize multiple Java Objects

hello dear colleagues,
I have a Garden class in which I serialize and deserialize multiple Plant class objects. The serializing is working but the deserializing is not working if a want to assign it to calling variable in the mein static method.
public void searilizePlant(ArrayList<Plant> _plants) {
try {
FileOutputStream fileOut = new FileOutputStream(fileName);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
for (int i = 0; i < _plants.size(); i++) {
out.writeObject(_plants.get(i));
}
out.close();
fileOut.close();
} catch (IOException ex) {
}
}
deserializing code:
public ArrayList<Plant> desearilizePlant() {
ArrayList<Plant> plants = new ArrayList<Plant>();
Plant _plant = null;
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
Object object = in.readObject();
// _plant = (Plant) object;
// TODO: ITERATE OVER THE WHOLE STREAM
while (object != null) {
plants.add((Plant) object);
object = in.readObject();
}
in.close();
} catch (IOException i) {
return null;
} catch (ClassNotFoundException c) {
System.out.println("Employee class not found");
return null;
}
return plants;
}
My invoking code:
ArrayList<Plant> plants = new ArrayList<Plant>();
plants.add(plant1);
Garden garden = new Garden();
garden.searilizePlant(plants);
// THIS IS THE PROBLEM HERE
ArrayList<Plant> dp = new ArrayList<Plant>();
dp = garden.desearilizePlant();
edit
I got a null Pointer exception
The solution of #NilsH is working fine, thanks!
How about serializing the entire list instead? There's no need to serialize each individual object in a list.
public void searilizePlant(ArrayList<Plant> _plants) {
try {
FileOutputStream fileOut = new FileOutputStream(fileName);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(_plants);
out.close();
fileOut.close();
} catch (IOException ex) {
}
}
public List<Plant> deserializePlant() {
List<Plants> plants = null;
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
plants = in.readObject();
in.close();
}
catch(Exception e) {}
return plants;
}
If that does not solve your problem, please post more details about your error.
It may not always be feasible to deserialize a whole list of objects (e.g., due to memory issues). In that case try:
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
filename));
while (true) {
try {
MyObject o = (MyObject) in.readObject();
// Do something with the object
} catch (EOFException e) {
break;
}
}
in.close();
Or using the Java SE 7 try-with-resources statement:
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(
filename))) {
while (true) {
MyObject o = (MyObject) in.readObject();
// Do something with the object
}
} catch (EOFException e) {
return;
}
If you serialize it to an array linear list, you can cast it back to an array linear list when deserializing it -- all other methods failed for me:
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
public class Program
{
public static void writeToFile(String fileName, Object obj, Boolean appendToFile) throws Exception
{
FileOutputStream fs = null;
ObjectOutputStream os = null;
try
{
fs = new FileOutputStream(fileName);
os = new ObjectOutputStream(fs);
//ObjectOutputStream.writeObject(object) inherently writes binary
os.writeObject(obj); //this does not use .toString() & if you did, the read in would fail
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
os.close();
fs.close();
}
catch(Exception e)
{
//if this fails, it's probably open, so just do nothing
}
}
}
#SuppressWarnings("unchecked")
public static ArrayList<Person> readFromFile(String fileName)
{
FileInputStream fi = null;
ObjectInputStream os = null;
ArrayList<Person> peopleList = null;
try
{
fi = new FileInputStream(fileName);
os = new ObjectInputStream(fi);
peopleList = ((ArrayList<Person>)os.readObject());
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch(EOFException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
os.close();
fi.close();
}
catch(Exception e)
{
//if this fails, it's probably open, so just do nothing
}
}
return peopleList;
}
public static void main(String[] args)
{
Person[] people = { new Person(1, 39, "Coleson"), new Person(2, 37, "May") };
ArrayList<Person> peopleList = new ArrayList<Person>(Arrays.asList(people));
System.out.println("Trying to write serializable object array: ");
for(Person p : people)
{
System.out.println(p);
}
System.out.println(" to binary file");
try
{
//writeToFile("output.bin", people, false); //serializes to file either way
writeToFile("output.bin", peopleList, false); //but only successfully read back in using single cast
} // peopleList = (ArrayList<Person>)os.readObject();
// Person[] people = (Person[])os.readObject(); did not work
// trying to read one at a time did not work either (not even the 1st object)
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("\r\n");
System.out.println("Trying to read object from file. ");
ArrayList<Person> foundPeople = null;
try
{
foundPeople = readFromFile("input.bin");
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if (foundPeople == null)
{
System.out.println("got null, hummm...");
}
else
{
System.out.println("found: ");
for(int i = 0; i < foundPeople.size(); i++)
{
System.out.println(foundPeople.get(i));
}
//System.out.println(foundPeople); //implicitly calls .toString()
}
}
}

Categories

Resources