How to Save/Load data from TableView in JavaFX - java

I have created a TableView that allows the user to enter information into the table. The issue I am having is that I need to save the information the user provided, and reload the same table, with the same information the next time the program is ran. I've been stuck for some time on this, if anyone can help I would greatly appreciate it. BELOW is my ObservableList and the methods I tried. I will include a screen capture of what the table looks like. I called the methods from button pushes the user would make.
//get Trail info
public static ObservableList<Stats> getTrailInfo(){
ObservableList<Stats> trailInfo = FXCollections.observableArrayList();
trailInfo.add(new Stats(trailList, timesHiked, daysHiked, hoursHiked, minutesHiked, milesHiked));
return trailInfo;
}
//I ATTEMPTED TO SAVE AND READ IT BACK USING THESE METHODS, BUT I DID NOT HAVE ANY LUCK
private static void write(ObservableList<Stats> stats) {
try {
// write object to file
OutputStream out = new FileOutputStream("TrailName.txt");
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(new ArrayList<Stats>(stats));
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static ObservableList<Stats> pull() {
try {
InputStream inputstream = new FileInputStream("TrailName.txt");
ObjectInputStream ois = new ObjectInputStream(inputstream);
List<Stats> list = (List<Stats>) ois.readObject() ;
return FXCollections.observableList(list);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return FXCollections.emptyObservableList();
}
[TableView ScreenShot][1]
[1]: https://i.stack.imgur.com/m0nyg.png

Does Stats implement java.io.Serializable? From the API docs from ObjectOutputStream:
Only objects that support the java.io.Serializable interface can be written to streams.
From the docs on Serializable:
Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized.

Related

Serialization throws InvalidClassExceptionn

I'm new serialization (and programming in general) so i don't really know what happens under the hood. I'm making an email client program and the class
FileHandlerObject is used to write and read email messages that i send. I maintain an ArrayList and it is read, updated with new email and then written again. I don't understand why it throws an InvalidClassException because the file contains an ArrayList so the casting should be no problem.
I'm maintaining an ArrayList because the writeObject() truncates the file every time it writes.(Let me know if im wrong here)
class FileHandlerObject implements MyFileHandler<EmailMessage>{
public void write(EmailMessage input){
try
{
FileInputStream fileInputStream=new FileInputStream("emails.ser");
ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream);
#SuppressWarnings("unchecked")
ArrayList<EmailMessage> messagelist= (ArrayList<EmailMessage>) objectInputStream.readObject();
objectInputStream.close();
messagelist.add(input);
FileOutputStream fileOutputStream = new FileOutputStream("emails.ser");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(messagelist);
objectOutputStream.flush();
objectOutputStream.close();
}
catch(FileNotFoundException f)
{
try{
FileOutputStream fileOutputStream = new FileOutputStream("emails.ser");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
ArrayList<EmailMessage> messagelist=new ArrayList<EmailMessage>();
messagelist.add(input);
objectOutputStream.writeObject(messagelist);
objectOutputStream.flush();
objectOutputStream.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
catch(IOException e){
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
public ArrayList<EmailMessage> read(){
try{
FileInputStream fileInputStream=new FileInputStream("emails.ser");
ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream);
#SuppressWarnings("unchecked")
ArrayList<EmailMessage> messagelist= (ArrayList<EmailMessage>) objectInputStream.readObject();
objectInputStream.close();
return messagelist;
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException c)
{
c.printStackTrace();
}
catch(ClassCastException c)
{
c.printStackTrace();
}
return null;
}
As the docs explain, this means one of a few things. The code you pasted does not give any insights about which of these mistakes you've made.
You saved some emails. Then, you edited the EmailMessage class, for example by adding a method or changing the name of a field, and then you ran the code again which ends up reading that file that was 'saved' with an old version of EmailMessage and which you are now trying to read with a new version. The java serialization mechanism can theoretically deal with versioning schemes but in practice it's a disaster. Ditch serialization, write your own protocol instead.
The EmailMessage class does not implement Serializable and does not have a no-args constructor. Give it a no-args constructor, and add implements Serializable to it.
Your classpath is incomplete; EmailMessage contains fields or methods that refer to some other class you wrote and it is not available on the classpath right now. Fix your classpath.

Workaround java.io.EOFException cause by ObjectInputStream [duplicate]

This question already has answers here:
java.io.FileNotFoundException when creating FileInputStream
(2 answers)
Closed 6 years ago.
For my application I want to use a Map to act as a database. To save and load a map, I am writing/reading it to/from database.ser using this 2 methods:
private synchronized void saveDB() {
try {
fileOut = new FileOutputStream(db);
out = new ObjectOutputStream(fileOut);
out.writeObject(accounts);
fileOut.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#SuppressWarnings("unchecked")
private void loadDB() {
try {
fileIn = new FileInputStream(db);
in = new ObjectInputStream(fileIn); // that is where error is produced if fileIn is empty
accounts = (Map<String, Client>) in.readObject();
in.close();
fileIn.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I want to load into Map when application starts, so I invoke method in constructor like this:
protected DriveatorImpl() {
accounts = new ConcurrentHashMap<String, Client>();
db = new File("C:/Users/eduar/git/Multy-Threaded-Bank-System/Bank-Services/database.ser");
// also, any suggestions how can I make path to a file more flexible in case I want to run Server side of an app on different machine?
if (!db.exists()) {
try {
db.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
loadDB(); // loads database when server start
}
I am aware of what causing an error, but I don't know what should I change in my design to avoid ObjectInputStream constructor receiving empty stream!
Any suggestions on what I can do differently?
Edit: I want to note that in fresh application run database.ser is empty since there was no entries made into Map yet.
Thank You!
First why the EOFExcpetion occur?
There are no contents in file or file is empty and you tried to read file.
You can avoid the EOFException for an empty file by checking file content length if it is less than or equal to zero means file is empty. another way to check if file is empty
Some code change and it worked for me.
#SuppressWarnings("unchecked")
private void loadDB() {
try {
if (db.length() <= 0) {
// if statement evaluates to true even if file doesn't exists
saveDB(); // save to a file an empty map
// if file doesn't exist, it creates a new one
// call loadDB inside constructor
}
FileInputStream fileIn = new FileInputStream(db);
ObjectInputStream in = new ObjectInputStream(fileIn); // that is where error is produced if fileIn is empty
in.readObject();
in.close();
fileIn.close();
System.out.println(accounts);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Get rid of the file.exists()/file.createNewFile() crap. All it is doing for you is masking the original FileNotFoundException problem, and turning into a thoroughly predictable EOFException because of trying to construct an ObjectInputStream around an empty stream. Handle the original problem. Don't just move it, or turn it into something else.

How can I ensure that my app's data doesn't get deleted when releasing an update?

My android app saves an array of Objects to cache using serializable, but when updates are released, the array is completely deleted and users have to re-do all input. What is the solution to this?
Thanks in advance
How did you store you serializable object to the cache? The package management system will keep the old data for an update installation of the app.
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream(
getCacheDir() + File.separator + "object"));
MyObject object = new MyObject();
object.setData(15);
object.setName("name");
objectOutputStream.writeObject(new MyObject());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (objectOutputStream != null) {
try {
objectOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Look into ActiveAndroid if you are fine with storing data on the device. Look into building out a restful API in the cloud if you want it to persist forever.

How to retrieve many objects from .dat File using Java?

I have admin account which should be able to add many users to a .dat file. Then I want to retrieve all the objects from the .dat file into a list for further programming.
public class User implements Serializable { //get and set methods }
This is hwo I am writing each object to the .dat file
public void addNewUser() throws Exception {
User newUser=new User();
newUser.name="test";
newUser.position="admin";
FileOutputStream outStream = new FileOutputStream("Users.dat", true);
ObjectOutputStream objectOutputFile = new ObjectOutputStream(outStream);
// Write the object to the file.
objectOutputFile.writeObject(newUser);
// Close the file.
objectOutputFile.close();
}
How can retrieve all the objects from the .dat file into ArrayList??
public class displayUsers { **//what to do??** }
You can either write the list object and read it as list. But since you're writing user objects individually, you can do something like this -
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Users.dat"));
Object object = null;
while ((object = ois.readObject()) != null) {
if (object instanceof User) {
User user = (User) object;
list.add(user);
}
}
Of course, you would need to take care of exceptions (like EOFException).
Generally it is bad practice to concatenate individual ObjectOutputStreams in a file without adding any lengths or delimiters. So better write all objects in one pass (and use ObjectOutputStream.reset in case your process is long-running and you fear memory leaks (otherwise ObjectOutputStream will keep a reference to every object it serialized before) or add them to a List and write it.
If you have to write it in multiple passes, I'd suggest to write the individual objects to a ByteArrayOutputStream first, and then use DataOutputStream to write the array prefixed by its length. That way, you can use DataInputStream to get out the individual byte arrays and use ByteArrayInputStream to deserialize them.
In case this does not work, you can try this solution (depending on the lookahead used by ObjectInputStream, this might not work for more complex objects with custom serialization formats, though, so use at your own risk):
public static void displayUsers() throws Exception {
FileInputStream fiis = new FileInputStream("Users.dat");
InputStream fis = new FilterInputStream(fiis) {
#Override
public void close() throws IOException {
// ignore
}
};
try {
while (true) {
ObjectInputStream in = new ObjectInputStream(fis);
User user = (User) in.readObject();
in.close();
System.out.println(user.name + "/" + user.position);
}
} catch (EOFException ex) {
// done
}
fiis.close();
}
List<User> listOfUser = new ArrayList<User>();
ObjectInputStream input = null;
try {
while (true) {
input = new ObjectInputStream(new FileInputStream("Users.dat"));
listOfUser.add(input.readObject());
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
input.close();
}

Reading from internal storage (deserialization)

I am using the following method to read from the internal storage:
private void deserialize(ArrayList<Alias>arrayList) {
try {
FileInputStream fis = openFileInput(filename);
ObjectInputStream ois = new ObjectInputStream(fis);
arrayList = (ArrayList<Alias>)ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
It reads the content of the file "filename" to the "arrayList".
The "serialize" method is as follows:
void serialize(ArrayList<Alias>arrayList) {
FileOutputStream fos;
try {
fos = openFileOutput(filename, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(arrayList);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
The problem is that I whenever I run my program again, the "arrayList" is empty. So I guess I am opening the file in wrong input mode.
My aim is to first get the array from the file, then modify it within the app, and then write the modified array back to the file.
Can someone please help me with my problem?
Thanks!
Can you post your pice of your source code? I think the way which you used to parse file content get issue.
Read here:
Android ObjectInputStream docs
I read that the method readObject() read the next object...i this that you must iterate with something like this:
MediaLibrary obj = null;
while ((obj = (MediaLibrary)objIn.readObject()) != null) {
libraryFromDisk.add(obj);
}

Categories