Serialize and deserialize objects and properties in Java - java

I have a problem with the serialization and deserialization of objects in Java, and I think it's because I do not really understand how it works. My program consists of some spreadsheets as in Excel, but by console. I have a class "Book" and a class "Page". In Book, I have declared a Page's HashMap and in Page I have a String's Hashmap (to simulate the cells). Now I want that book to be persistent and for that what I do is serialize the "libro" object (Book instance):
try {
FileOutputStream fileOut =
new FileOutputStream("H:\\Users\\thero\\Desktop\\bin\\libro.bin");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(libro);
out.close();
fileOut.close();
System.out.printf("Se ha guardado el libro correctamente");
}
catch (IOException i) {
i.printStackTrace();
}
This code is included in a method of a class called "Salvar" that I call from the main. At the same time I have a class "Cargar" with the opposite method:
try {
FileInputStream fileIn = new FileInputStream("H:\\Users\\thero\\Desktop\\bin\\libro.bin");
ObjectInputStream in = new ObjectInputStream(fileIn);
libro = (Book) in.readObject();
in.close();
fileIn.close();
} catch (IOException i) {
i.printStackTrace();
} catch (ClassNotFoundException ex) {
Logger.getLogger(Cargar.class.getName()).log(Level.SEVERE, null, ex);
}
I also call this method from the main, and when executing it, no exception jumps. However, it seems that it only loads the Book instance, but it does not load the Hashmap property, and therefore it does not load the created spreadsheets with the cells. Where is the problem? This is my class Book code:
package javacalc.items;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Book implements Serializable{
private HashMap<String, Page> libro;
private Page activePage;
private String nameActivePage;
public Book(){
this.libro = new HashMap<>();
}
public List <String> getListPages() {
ArrayList <String> myList = new ArrayList<>();
for (String s: this.libro.keySet())
myList.add(s);
return myList;
}
public void setListPages(String s, Page p) {
this.libro.put(s,p);
}
public void deletePage(String s){
this.libro.remove(s);
}
public Page getActivePage() {
return activePage;
}
public boolean setActivePage(String activePage) {
Page p = this.libro.get(activePage);
this.nameActivePage = activePage;
this.activePage = p;
return true;
}
public String getNameActivePage(){
return nameActivePage;
}
public boolean containsPage(String s){
return libro.containsKey(s);
}
public HashMap<String, Page> getLibro() {
return this.libro;
}
}
Thank you.
Okey I think I resolved correctly I just made some changes in "Cargar":
try {
String ruta = comando.substring(8, comando.length()-1).trim();
FileInputStream fileIn = new FileInputStream(ruta);
ObjectInputStream in = new ObjectInputStream(fileIn);
Book libro_c = (Book) in.readObject();
libro.setLibro(libro_c.getLibro());
in.close();
fileIn.close();
Now it works! Thanks for your help!!

Related

i can not write more than one object on a file in java

import java.io.*;
import java.util.ArrayList;
public class Main {
static ArrayList<test> testArrey = new ArrayList<test>();
public static void main(String[] args) {
output(new test(18, "aren"));
output(new test(22, "ahmad"));
input();
read();
}
public static void read() {
for (test a : testArrey) {
System.out.println(a.age);
}
}
public static void input() {
try {
FileInputStream fileInput = new FileInputStream("open.ses");
ObjectInputStream ObjectInput = new ObjectInputStream(fileInput);
Object a1 = ObjectInput.readObject();
test b1 = (test) a1;
testArrey.add(b1);
Object a2 = ObjectInput.readObject();
test b2 = (test) a2;
testArrey.add(b2);
ObjectInput.close();
} catch (Exception ex) {
System.out.println("input error");
ex.printStackTrace();
}
}
public static void output(test a) {
try {
FileOutputStream fileOut = new FileOutputStream("open.ses");
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(a);
objectOut.close();
} catch (Exception ex) {
System.out.println("output error");
ex.printStackTrace();
}
}
public static class test implements Serializable {
int age ;
String name ;
public test(int age , String name ) {
this.age = age;
this.name = name;
}
}
}
as you can see a called output() method two time with new to object of (test)as argument ,and it must write two object on (open.ses)file but when i want to call (.readobject)two times it gives me an error that says one object is saved ............
how to write more than one object with the help of method like the one i wrote ??

Why is this Class' object not serialized properly in different processes?

Context
I made a Java application, and need to run two instances of that application, synchronizing some of their attributes via socket each time there's some change. To communicate those changes, Serializable objects are sent through a socket using ObjectStreams (input and output) using read/writeUTF() for an identifier, and read/writeObject() and flush(). The app is the exact same .jar, run twice with some changes like having different ports and ip (if necessary).
Problem
I noticed that objects of some of my classes (e.g. Notification) were sent and received without any troubles, but objects from another class (RegisteredUsers) weren't sent (or received) properly. So I ran some tests to send objects between the two apps and found that the object is being sent and isn't null, it's attribute (a HashMap<String,User>) is also being sent and isn't null, but is always empty.
So I decided to scale it down to what the problem was exactly: I'm trying to write an object through a Stream, and read it in a different process of the same .jar, and with most classes it seems to work, but it doesn't with one.
There seems to be something I'm missing or don't understand about this serialization process, if the object is written and read during the execution of the same process it works, but not if this object is read on another instance of the same app. I even added a HashMap to Notification with the same creation process, but it still works, I really don't get it, what am I missing?
Code
I have taken some code from the bigger app and trimmed it down to the basic problem if anyone wants to test it. To reproduce the errors, run Main1, which will create the two files with an object persisted in each one (one with a Notification object and the other with a RegisteredUsers object) and shows their information, then Main2, which reads them from the files and shows their information, and the problem should be printed. That being that reg3's HashMap is empty and thus neither of the Users are registered.
Main1
public class Main1 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg1 = new RegisteredUsers();
RegisteredUsers reg2 = new RegisteredUsers();
reg1.register("Name1", "127.0.0.1");
reg1.register("Name2", "127.0.0.1");
try {
pers.writeReg(reg1, regFile);
} catch (IOException e) {
System.out.println("Error writing registry.");
}
try {
reg2 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
System.out.println("Original registry: ");
System.out.println(reg1.isRegistered("Name1") + " " + reg1.isRegistered("Name2"));
System.out.println("Registry read from file: ");
System.out.println(reg2.isRegistered("Name1") + " " + reg2.isRegistered("Name2"));
Notification noti1 = new Notification("Name", "127.0.0.1");
Notification noti2 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
pers.writeNotif(noti1, notificationFile);
} catch (IOException e) {
System.out.println("Error writing notification.");
}
try {
noti2 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Original notification: ");
System.out.println(noti1.getAttributes().get(0) + " " + noti1.getAttributes().get(1));
System.out.println(noti1.getMap());
System.out.println("Notification read from file: ");
System.out.println(noti2.getAttributes().get(0) + " " + noti2.getAttributes().get(1));
System.out.println(noti2.getMap());
}
}
Main2
public class Main2 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg3 = new RegisteredUsers();
try {
reg3 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
if (reg3 == null) {
System.out.println("reg3 is null");
}
if (reg3.getMap() == null)
System.out.println("reg3 has a null map");
if (reg3.getMap().isEmpty())
System.out.println("reg3 has an empty map");
System.out.println("Registry read from file on another process: ");
System.out.println(reg3.isRegistered("Name1") + " " + reg3.isRegistered("Name2"));
Notification noti3 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
noti3 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Notification read from file on another process: ");
System.out.println(noti3.getAttributes().get(0) + " " + noti3.getAttributes().get(1));
System.out.println(noti3.getMap());
}
}
A Class to persist the objects in the files:
public class Persistence {
public void writeReg(RegisteredUsers regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public RegisteredUsers readReg(String file) throws IOException {
RegisteredUsers regus = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
regus = (RegisteredUsers) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return regus;
}
public void writeNotif(Notification regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public Notification readNotif(String file) throws IOException {
Notification notif = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
notif = (Notification) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return notif;
}
}
RegisteredUsers
public class RegisteredUsers implements Serializable {
private static HashMap<String, User> users;
public RegisteredUsers() {
users = new HashMap<String, User>();
}
public HashMap<String, User> getMap() {
return users;
}
public boolean isRegistered(String name) {
User us = users.get(name);
return us != null;
}
public void register(String name, String ip) {
users.put(name, new User(name, ip, false));
}
}
Notification
public class Notification implements Serializable {
private ArrayList<String> attributes;
private HashMap<String, User> map = new HashMap<>();
public Notification() {
}
public Notification(String name, String ip) {
attributes = new ArrayList<String>();
attributes.add(0, name);
attributes.add(1, ip);
map.put(ip, new User(name, ip, false));
}
public ArrayList<String> getAttributes() {
return attributes;
}
public HashMap<String, User> getMap() {
return map;
}
}
User
public class User implements Serializable {
private String name;
private String ip;
private boolean connection_state;
public User(String name, String ip, boolean connection_state) {
this.name = name;
this.ip = ip;
this.connection_state = connection_state;
}
}
In java static fields are implicitly transient, and transient fields are not serialized.
If you modify the RegisterdUsers to
public class RegisteredUsers implements Serializable {
private HashMap<String, User> users; // static modifier is removed
...
}
The serialization will work.

Using same Map in several classes after Serialization?

My app is saving a hashmap before it stops and when it starts again loads the same hashmap so changes could be made to it. I am using Serialization.
Storage class:
public class Storage {
private Map<String, String> storage;
private String projectStorageFilePath;
public Storage() {
this.storage = new ConcurrentHashMap<String, String>();
makeDir();
}
/**
* If the file in which the map objects will be saved doesn't exist in the
* user home directory it creates it.
*/
private void makeDir() {
File projectHomeDir = new File(System.getProperty("user.home"), ".TestMap");
String projectHomeDirPath = projectHomeDir.getAbsolutePath();
File projectStorageFile = new File(projectHomeDirPath, "storage.save");
projectStorageFilePath = projectStorageFile.getAbsolutePath();
if (!projectHomeDir.exists()) {
projectHomeDir.mkdir();
try {
projectStorageFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#SuppressWarnings("unchecked")
public boolean load() {
boolean isLoaded = false;
ObjectInputStream ois = null;
try {
File file = new File(projectStorageFilePath);
if (file.length() != 0) {
//loading the map
ois = new ObjectInputStream(new FileInputStream(file));
storage = (ConcurrentHashMap<String, String>) ois.readObject();
isLoaded = true;
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != ois) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return isLoaded;
}
public boolean save() {
boolean isSaved = false;
ObjectOutputStream oos = null;
try {
//saving
oos = new ObjectOutputStream(new FileOutputStream(projectStorageFilePath));
oos.writeObject(storage);
isSaved = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (null != oos) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return isSaved;
}
public Map<String, String> getStorage() {
return this.storage;
}
}
The class in which I am trying to do something with that hashmap:
public class DoSomethingWithMap {
private Map<String, String> storage;
public DoSomethingWithMap(Map<String, String> storage) {
this.storage = storage;
}
public void addToMap(String key, String value) {
this.storage.put(key, value);
}
public void printMap() {
System.out.println(this.storage);
}
}
When I run it the first time it works fine:
public class Main {
public static void main(String[] args) {
Storage s = new Storage();
DoSomethingWithMap something = new DoSomethingWithMap(s.getStorage());
if (s.load()) {
System.out.println(s.getStorage());
}
something.addToMap("2", "test2");
something.addToMap("4", "test4");
something.addToMap("5", "test5");
if (s.save()) {
System.out.println(s.getStorage());
}
}
}
Output:
{} //empty map which is ok because it has never been saved before
{3=test3, 4=test4, 5=test5} //changes during runtime are saved
The problem is when I start Main again and try to make changes to the saved map:
public static void main(String[] args) {
Storage s = new Storage();
DoSomethingWithMap something = new DoSomethingWithMap(s.getStorage());
if (s.load()) {
System.out.println(s.getStorage());
}
something.printMap();
something.addToMap("6", "newTest");
something.addToMap("7", "newTest");
something.addToMap("8", "newTest");
something.printMap();
if (s.save()) {
System.out.println(s.getStorage());
}
}
Output:
{3=test3, 4=test4, 5=test5} //loading the map works fine
{} //here it should be same as previous line but is not
{6=newTest, 7=newTest, 8=newTest} //DoSomethingWithMap.printMap is printing only the changes during runtime
{3=test3, 4=test4, 5=test5} // changes during runtime are not saved
It is obvious DoSomethingWithMap class is not using the map which was given to it. Why? Which map is using? How I can fix that?
Thank you.
You are creating a new instance of the Map in your load method:
storage = (ConcurrentHashMap<String, String>) ois.readObject();
To fix you can clear the current map and then add all the values from the loaded one:
//loading the map
ois = new ObjectInputStream(new FileInputStream(file));
storage.clear();
storage.putAll((ConcurrentHashMap<String, String>) ois.readObject());
To prevent such error in the future, you could make those fields final and thus you will get error reports.

Cannot write to file ArrayList with class objects

I've reasearched a lot of websites and I couldn't find answear. I'm trying to write to .txt file my ArrayList which constains class objects. Every time I try to do it I`m getting exception. With reading is the same problem. Here is my code:
public static void write()
{
try
{
FileOutputStream out = new FileOutputStream("clients.txt");
ObjectOutputStream oout = new ObjectOutputStream(out);
oout.writeObject(lista);
oout.close();
}
catch(Exception ioe)
{
System.out.println("writing Error!");
welcome();
}
}
public static void read()
{
try
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("clients.txt"));
lista = (List<Client>) ois.readObject();
}
catch (ClassNotFoundException ex)
{
System.out.println("Koniec pliku");
}
catch(IOException ioe)
{
System.out.println("Error!");
welcome();
}
}
I guess you're looking for the Serializable interface of Java. In order to save objects you're class have to implement it.
The question is: What execatly do you want to save? The content of the list so that you can save it in a file and load it afterwards?
This simple example works for me (for the scenario I mention above):
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public User(String name, int ag) {
this.name = name;
this.age = age;
}
#Override
public String toString() {
return (this.name + ' ' + this.age);
}
}
public class Main {
private static List<User> l;
public static void main(String[] args) {
l = new ArrayList<User>();
user1 = new User("John", 22);
user2 = new User("Jo", 33);
l.add(user1);
l.add(user2);
write();
}
public static void write() {
try {
FileOutputStream fos = new FileOutputStream("testout.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(l);
oos.close();
} catch (Exception ioe) {
System.out.println("writing Error!");
}
}
}
Ok I have changed a bit (not each function just the read and write functionality) and this work.
Link to Code.
One important thing is that the Scanner class is not serializable. Therefore, you have to make it static for example.

How to sort a text file and save it using java?

I have been asked to make a quiz and in the end of the quiz, what I want to keep are in two separate arrays names[] and scores[]. I have been asked to save the scores in a file using input and output. I have managed to do everything and successfully output the results and save it into the files (e.g. highscores.txt)
the results are saved like this:
4
name10
name5
name4
name2
the first line indicates how many scores there are in the file as every person who plays the quiz has their score saved.
What I am struggling to do is sort the scores to be placed in order of highest to lowest.
I have tried sorting the scores before they are saved in the file but the older scores in the file will not be sorted anymore. Example:
8
newname10
newname9
newname8
newname7
name10
name5
name4
name2
im only a beginner so go easy...
Well, because you don't use any kind of formatting to easily distinguish between username and score (eg: [username]:[score]) you've the problem to separate these two information from each other afterwards.
Anyhow - you need to load the data and reorder them trying to separate the username from the score. Read the file line my line and split the name from the score using regexp (in hope that the user name contains only letters): Pattern.compile("(\w+)(\d+)"). You can then use Matcher to get group 1 (the Name) and group 2 (the score). Then you can compare the score and reorder the List
What you should do is to create class Person which implements Comparable<Person> and if you are little bit lazy and the amount of data is not large Serializable too.
Then put everything inside TreeSet<Person> and write methods which serialize the TreeSet and deserialize it too.
Like this:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.TreeSet;
public class Person implements Comparable<Person>, Serializable {
private String name;
private int score;
public Person(String name, int score) {
this.name = name;
this.score = score;
addPerson(this);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
#Override
public int compareTo(Person o) {
return score - o.score;
}
#Override
public String toString() {
return "Person [name=" + name + ", score=" + score + "]";
}
private static TreeSet<Person> classExtension = new TreeSet<Person>();
private static void addPerson(Person person) {
classExtension.add(person);
}
private static void removePerson(Person person) {
classExtension.remove(person);
}
private static void showExtension() {
for (Person person : classExtension)
System.out.println(person);
}
public static void serialize() {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream("Person.ser");
oos = new ObjectOutputStream(fos);
oos.writeObject(classExtension);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null)
oos.close();
} catch (IOException e) {
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
}
}
}
public static void deserialize(){
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("Person.ser");
ois = new ObjectInputStream(fis);
classExtension = (TreeSet<Person>) ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
// zasoby zwalniamy w finally
try {
if (ois != null) ois.close();
} catch (IOException e) {}
try {
if (fis != null) fis.close();
} catch (IOException e) {}
}
}
}
If you're already able to sort the results before writing them to the file, why don't you read all the file before updating It? Then you can put the old data stored in your data structure with the new data,and sort them alla together. Then you should overwrite the old file with the data you already have.
This way could be expensive if your file has a lot of record.
The best way could be to use a collection that keep items in order. Take a look to PriorityQueue class. Then just store it into the file,and load It before adding new elements.
You can write the PriorityQueue to a file using an ObjectOutputStream and read it back with an ObjectInputStream.
This little program should do the Job.
Bear in mind that this really just sorts a text-file. If you need further processing according to your problem, modify it.
public class LineReader {
public static void main(String[] args) {
String file = args[0];
List<String> _list = new ArrayList<String>();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
for (String line; (line = br.readLine()) != null;) {
_list.add(line);
}
} catch (Exception ex) {
}
java.util.Collections.sort(_list, String.CASE_INSENSITIVE_ORDER);
try(FileWriter writer = new FileWriter(file)) {
for (String str : _list) {
writer.write(str + "\n");
}
writer.close();
} catch (IOException ex) {
}
}
}

Categories