如何为我的项目实现 Serializable 以具有持久性?
How to implement Serializable for my project to have persistence?
我的主要方法:
public class ToDoList extends Application{
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) throws Exception {
Pane pane = FXMLLoader.load(getClass().getResource("ToDoList.fxml"));
Scene scene = new Scene(pane);
scene.getStylesheets().add(getClass().getResource("ToDoListStyle.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("Plan yourself");
primaryStage.show();
}
}
然后控制器的一部分:
ObservableList<EventsBean> dataList = FXCollections.observableArrayList();
@Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("The pane loaded");
List<String> myList;
try {
myList = Files.lines(Paths.get("src/com/todolist/EventsList.txt")).collect(Collectors.toList());
eventsSelector.setItems(FXCollections.observableArrayList(myList));
} catch (IOException e) {
System.out.println("Don t find file");
}
removeCol.setCellFactory(CheckBoxTableCell.forTableColumn(removeCol));
eventCol.setCellValueFactory(new PropertyValueFactory<EventsBean, String>("event"));
dateCol.setCellValueFactory(new PropertyValueFactory<EventsBean, LocalDate>("date"));
doneCol.setCellValueFactory(new PropertyValueFactory<EventsBean, String>("done"));
doneCol.setCellFactory(TextFieldTableCell.<EventsBean>forTableColumn());
doneCol.setOnEditCommit((CellEditEvent<EventsBean, String> t) -> {
((EventsBean) t.getTableView().getItems().get(t.getTablePosition().getRow()))
.setDone(t.getNewValue());
});
observationCol.setCellValueFactory(new PropertyValueFactory<EventsBean, String>("observation"));
removeCol.setCellValueFactory(cellData -> cellData.getValue().selectedProperty());
observationCol.setCellFactory(TextFieldTableCell.<EventsBean>forTableColumn());
observationCol.setOnEditCommit((CellEditEvent<EventsBean, String> t) -> {
((EventsBean) t.getTableView().getItems().get(t.getTablePosition().getRow()))
.setObservation(t.getNewValue());
});
observationCol.setSortable(false);
eventsTable.setItems(dataList);
eventsTable.setEditable(true);
bttnAddEvent.setOnAction((ActionEvent e) -> {
try {
text = eventsSelector.getValue().toString();
dataList.add(new EventsBean(text, isoDate, "", "", false));
} catch (Exception e1) {
System.out.println("Nothing selected");
}
});
bttnRemove.setOnAction((ActionEvent e) -> {
ObservableList<EventsBean> dataListToRemove = FXCollections.observableArrayList();
for (EventsBean bean : dataList) {
if (bean.getSelected()) {
dataListToRemove.add(bean);
}
}
dataList.removeAll(dataListToRemove);
// Below code it is for delete a focused row
// EventsBean selectedItem = eventsTable.getSelectionModel().getSelectedItem();
// eventsTable.getItems().remove(selectedItem);
});
}
然后是 EventsBean:
public class EventsBean {
private SimpleStringProperty event;
private SimpleObjectProperty<LocalDate> date;
private SimpleStringProperty done;
private SimpleStringProperty observation;
private SimpleBooleanProperty selected;
public EventsBean(String event, LocalDate date, String done, String observation, boolean selected) {
this.event = new SimpleStringProperty(event);
this.date = new SimpleObjectProperty<LocalDate>(date);
this.done = new SimpleStringProperty(done);
this.observation = new SimpleStringProperty(observation);
this.selected = new SimpleBooleanProperty(selected);
}
// Getters and Setters ...
我想序列化 table 中的数据。可序列化对象我认为是ObservableList中的dataList。我的问题是在哪里实现 Serializable 接口?这是我坚持的最佳解决方案吗?
提前致谢!
你应该首先问问自己是否真的想在这里使用对象序列化。使用不同的持久性方法可能会更好:例如使用 JSON 编组库,例如 GSON。大多数此类库仅使用对象的 get
和 set
方法来查找数据,因此只需很少的额外代码就可以与您的 EventsBean
class 一起使用。
如果你确实想使用Java对象序列化,你需要制作EventsBean
classSerializable
。通常这很简单,但是您 运行 遇到的问题是 JavaFX 属性 class 没有实现 Serializable
,所以天真地让 EventsBean
实现Serializable
并尝试序列化它的实例将生成 运行 时间异常。您需要使用自定义序列化来执行此操作。
首先,使 JavaFX 属性 transient
,因此默认序列化机制不会尝试序列化它们,然后定义自定义 readObject
和 writeObject
方法定义对象应如何序列化:
public class EventsBean implements Serializable {
private transient SimpleStringProperty event;
private transient SimpleObjectProperty<LocalDate> date;
private transient SimpleStringProperty done;
private transient SimpleStringProperty observation;
private transient SimpleBooleanProperty selected;
// constructors...
// example get/set/property methods:
public StringProperty eventProperty() {
return event ;
}
public final String getEvent() {
return eventProperty().get();
}
public final void setEvent(String event) {
eventProperty().set(event);
}
// etc. for other properties...
// custom serialization:
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeObject(getEvent()); // write event as a plain String
s.writeObject(getDate());
s.writeObject(getDone());
s.writeObject(getObservation());
s.writeBoolean(isSelected());
}
// custom deserialization:
private void readObject(ObjectInputStream s) throws IOException {
s.defaultReadObject();
this.event = new SimpleStringProperty((String)s.readObject());
this.data = new SimpleObjectProperty<>((LocalDate)s.readObject());
this.done = new SimpleStringProperty((String)s.readObject());
this.observation = new SimpleStringProperty((String)s.readObject());
this.selected = new SimpleBooleanProperty(s.readBoolean());
}
}
最后,您还需要注意 ObservableList
实现通常不可序列化,因此您需要序列化一个 "regular" 列表才能序列化数据,即:
ObjectOutputStream s = ... ;
s.writeObject(new ArrayList<EventsBean>(dataList));
并回读:
ObjectInputStream s = ... ;
dataList.setAll((List<EventsBean>)s.readObject());
我的主要方法:
public class ToDoList extends Application{
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) throws Exception {
Pane pane = FXMLLoader.load(getClass().getResource("ToDoList.fxml"));
Scene scene = new Scene(pane);
scene.getStylesheets().add(getClass().getResource("ToDoListStyle.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("Plan yourself");
primaryStage.show();
}
}
然后控制器的一部分:
ObservableList<EventsBean> dataList = FXCollections.observableArrayList();
@Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("The pane loaded");
List<String> myList;
try {
myList = Files.lines(Paths.get("src/com/todolist/EventsList.txt")).collect(Collectors.toList());
eventsSelector.setItems(FXCollections.observableArrayList(myList));
} catch (IOException e) {
System.out.println("Don t find file");
}
removeCol.setCellFactory(CheckBoxTableCell.forTableColumn(removeCol));
eventCol.setCellValueFactory(new PropertyValueFactory<EventsBean, String>("event"));
dateCol.setCellValueFactory(new PropertyValueFactory<EventsBean, LocalDate>("date"));
doneCol.setCellValueFactory(new PropertyValueFactory<EventsBean, String>("done"));
doneCol.setCellFactory(TextFieldTableCell.<EventsBean>forTableColumn());
doneCol.setOnEditCommit((CellEditEvent<EventsBean, String> t) -> {
((EventsBean) t.getTableView().getItems().get(t.getTablePosition().getRow()))
.setDone(t.getNewValue());
});
observationCol.setCellValueFactory(new PropertyValueFactory<EventsBean, String>("observation"));
removeCol.setCellValueFactory(cellData -> cellData.getValue().selectedProperty());
observationCol.setCellFactory(TextFieldTableCell.<EventsBean>forTableColumn());
observationCol.setOnEditCommit((CellEditEvent<EventsBean, String> t) -> {
((EventsBean) t.getTableView().getItems().get(t.getTablePosition().getRow()))
.setObservation(t.getNewValue());
});
observationCol.setSortable(false);
eventsTable.setItems(dataList);
eventsTable.setEditable(true);
bttnAddEvent.setOnAction((ActionEvent e) -> {
try {
text = eventsSelector.getValue().toString();
dataList.add(new EventsBean(text, isoDate, "", "", false));
} catch (Exception e1) {
System.out.println("Nothing selected");
}
});
bttnRemove.setOnAction((ActionEvent e) -> {
ObservableList<EventsBean> dataListToRemove = FXCollections.observableArrayList();
for (EventsBean bean : dataList) {
if (bean.getSelected()) {
dataListToRemove.add(bean);
}
}
dataList.removeAll(dataListToRemove);
// Below code it is for delete a focused row
// EventsBean selectedItem = eventsTable.getSelectionModel().getSelectedItem();
// eventsTable.getItems().remove(selectedItem);
});
}
然后是 EventsBean:
public class EventsBean {
private SimpleStringProperty event;
private SimpleObjectProperty<LocalDate> date;
private SimpleStringProperty done;
private SimpleStringProperty observation;
private SimpleBooleanProperty selected;
public EventsBean(String event, LocalDate date, String done, String observation, boolean selected) {
this.event = new SimpleStringProperty(event);
this.date = new SimpleObjectProperty<LocalDate>(date);
this.done = new SimpleStringProperty(done);
this.observation = new SimpleStringProperty(observation);
this.selected = new SimpleBooleanProperty(selected);
}
// Getters and Setters ...
我想序列化 table 中的数据。可序列化对象我认为是ObservableList中的dataList。我的问题是在哪里实现 Serializable 接口?这是我坚持的最佳解决方案吗?
提前致谢!
你应该首先问问自己是否真的想在这里使用对象序列化。使用不同的持久性方法可能会更好:例如使用 JSON 编组库,例如 GSON。大多数此类库仅使用对象的 get
和 set
方法来查找数据,因此只需很少的额外代码就可以与您的 EventsBean
class 一起使用。
如果你确实想使用Java对象序列化,你需要制作EventsBean
classSerializable
。通常这很简单,但是您 运行 遇到的问题是 JavaFX 属性 class 没有实现 Serializable
,所以天真地让 EventsBean
实现Serializable
并尝试序列化它的实例将生成 运行 时间异常。您需要使用自定义序列化来执行此操作。
首先,使 JavaFX 属性 transient
,因此默认序列化机制不会尝试序列化它们,然后定义自定义 readObject
和 writeObject
方法定义对象应如何序列化:
public class EventsBean implements Serializable {
private transient SimpleStringProperty event;
private transient SimpleObjectProperty<LocalDate> date;
private transient SimpleStringProperty done;
private transient SimpleStringProperty observation;
private transient SimpleBooleanProperty selected;
// constructors...
// example get/set/property methods:
public StringProperty eventProperty() {
return event ;
}
public final String getEvent() {
return eventProperty().get();
}
public final void setEvent(String event) {
eventProperty().set(event);
}
// etc. for other properties...
// custom serialization:
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeObject(getEvent()); // write event as a plain String
s.writeObject(getDate());
s.writeObject(getDone());
s.writeObject(getObservation());
s.writeBoolean(isSelected());
}
// custom deserialization:
private void readObject(ObjectInputStream s) throws IOException {
s.defaultReadObject();
this.event = new SimpleStringProperty((String)s.readObject());
this.data = new SimpleObjectProperty<>((LocalDate)s.readObject());
this.done = new SimpleStringProperty((String)s.readObject());
this.observation = new SimpleStringProperty((String)s.readObject());
this.selected = new SimpleBooleanProperty(s.readBoolean());
}
}
最后,您还需要注意 ObservableList
实现通常不可序列化,因此您需要序列化一个 "regular" 列表才能序列化数据,即:
ObjectOutputStream s = ... ;
s.writeObject(new ArrayList<EventsBean>(dataList));
并回读:
ObjectInputStream s = ... ;
dataList.setAll((List<EventsBean>)s.readObject());