Issue
I'm new to programming, what i want to do is read/write data that are stored in a ObservableList
, the data are from Student class which are Strings (firstName and lastName), and also i have a TableView to display the data.
Here is my code:
Student Class:
import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;
public class Student implements Serializable {
private SimpleStringProperty fname;
private SimpleStringProperty lname;
Student() {
this("","");
}
Student(String fn, String ln) {
this.fname = new SimpleStringProperty(fn);
this.lname = new SimpleStringProperty(ln);
}
public void setFirstName(String f) {
fname.set(f);
}
public String getFirstName() {
return fname.get();
}
public void setLastName(String l) {
lname.set(l);
}
public String getLastName() {
return lname.get();
}
@Override
public String toString() {
return String.format("%s %s", getFirstName(), getLastName());
}
}
And here is my code for inputing data using TextFields:
@FXML
ObservableList<Student> data = FXCollections.observableArrayList();
//Just to input the data
@FXML
private void handleButtonAction(ActionEvent event) {
if(!"".equals(txtFirstName.getText()) && !"".equals(txtLastName.getText())){
data.add(
new Student(txtFirstName.getText(),
txtLastName.getText()
));
}
txtFirstName.clear();
txtLastName.clear();
// System.out.println(data);
}
And here is the problem...
Reading/Writing the ObservableList:
@FXML
private void HandleMenuSaveAction(ActionEvent event) {
try {
FileOutputStream f = new FileOutputStream(new File("saveStudentList.txt"));
ObjectOutputStream o = new ObjectOutputStream(f);
o.writeObject(data);
o.close();
f.close();
System.out.println("File Saved Successfully.");
} catch (FileNotFoundException ex) {
System.err.println("Save: File not found.");
} catch (IOException ex) {
System.err.println("Save: Error initializing stream.");
ex.printStackTrace();
}
}
@FXML
private void HandleMenuLoadAction(ActionEvent event) {
try {
FileInputStream fi = new FileInputStream(new File("saveStudentList.txt"));
ObjectInputStream oi = new ObjectInputStream(fi);
data = (ObservableList) oi.readObject();
System.out.println(data.toString());
//Refresh the Table everytime we load data
oi.close();
fi.close();
} catch (FileNotFoundException ex) {
System.err.println("Load: File not found.");
} catch (IOException ex) {
System.err.println("Load: Error initializing stream.");
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
This is causing me java.io.NotSerializableException
,
Does anyone have an idea how to change my code so that it works?
Solution
implement custom serialisation for the Student
object (see https://stackoverflow.com/a/7290812/2991525) and copy the contents of the ObservableList
to a ArrayList
to create a serializable list:
public class Student implements Serializable {
private void writeObject(ObjectOutputStream out)
throws IOException {
out.writeObject(getFirstName());
out.writeObject(getLastName());
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
fname = new SimpleStringProperty((String) in.readObject());
lname = new SimpleStringProperty((String) in.readObject());
}
...
}
(De)serialisation example
ObservableList<Student> students = FXCollections.observableArrayList();
for(int i = 0; i < 100; i++) {
students.add(new Student("Mark"+i, "Miller"+i));
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// write list
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(new ArrayList<>(students));
}
students = null; // make sure the old reference is no longer available
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
// read list
try (ObjectInputStream ois = new ObjectInputStream(bis)){
students = FXCollections.observableList((List<Student>) ois.readObject());
}
System.out.println(students);
Answered By - fabian
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)