I'm having trouble with Java FX i'm currently trying to serialize an object and for that i'm creating a class that convert object from javaFX to serializable object. But when i'm trying to load back object i get
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.control.MenuItem.fire(MenuItem.java:462)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771)
... 43 more
Caused by: java.lang.UnsupportedOperationException
at java.util.AbstractList.add(Unknown Source)
at java.util.AbstractList.add(Unknown Source)
at view.OverviewInterroController.handleLoad(OverviewInterroController.java:172)
... 53 more
The code that cause it :
package model;
import java.io.Serializable;
import java.util.ArrayList;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
public class QuestionSerializable implements Serializable {
private final String question;
private final String typeReponse;
private final int nbLignesReponse;
private final ArrayList<String> reponseData = new ArrayList<String>();
public QuestionSerializable(QuestionModel model)
{
this.question = model.getQuestion().getValue();
this.typeReponse = model.getTypeReponse().getValue();
this.nbLignesReponse = model.getNbLignesReponse().getValue();
for(StringProperty val : model.getReponseData().getValue())
{
reponseData.add(val.getValue());
}
}
public QuestionModel convert()
{
QuestionModel qm = new QuestionModel(question);
qm.getNbLignesReponse().setValue(this.nbLignesReponse);
qm.getTypeReponse().setValue(typeReponse);
ObjectProperty<ObservableList<StringProperty>> reponseData2 =qm.getReponseData();
for(String val : reponseData)
{
reponseData2.getValue().add(new SimpleStringProperty(val));
}
return qm;
}
}
And specially :
ObjectProperty<ObservableList<StringProperty>> reponseData2 =qm.getReponseData();
for(String val : reponseData)
{
reponseData2.getValue().add(new SimpleStringProperty(val));
}
And the OverviewController
package view;
import java.io.File;
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.util.ArrayList;
import com.itextpdf.text.xml.simpleparser.handler.NeverNewLineHandler;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.FileChooser;
import model.QuestionModel;
import model.QuestionSerializable;
import principale.Main;
public class OverviewInterroController {
@FXML
private TableView<QuestionModel> questionTable;
@FXML
private TableColumn<QuestionModel,String> questionColumn;
@FXML
private Label questionLabel;
@FXML
private Label typeLabel;
@FXML
private Label nbLigneLabel;
@FXML
private TableView<StringProperty> reponseTable;
@FXML
private TableColumn<ObservableList<StringProperty>,String> reponseColumn;
// Reference to the main application.
private Main mainApp;
@FXML
private void initialize()
{
questionColumn.setCellValueFactory(cellData -> cellData.getValue().getQuestion());
showQuestionDetails(null);
questionTable.getSelectionModel().selectedItemProperty().addListener(
(observable,oldvalue,newValue)-> showQuestionDetails(newValue));
}
public void showReponseTable(QuestionModel question)
{
if(question.getTypeReponse().getValue().equals("Cocher"))
{
reponseTable.setItems(question.getReponseData().getValue());
reponseColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
reponseTable.setVisible(true);
}else
{
this.reponseTable.setVisible(false);
}
}
public void setMainApp(Main mainApp) {
this.mainApp = mainApp;
questionTable.setItems(mainApp.getQuestionData());
}
public void handleImprimer()
{
mainApp.showImprimerDialog();
}
public void handleClose()
{
System.exit(0);
}
public void showQuestionDetails(QuestionModel question)
{
if(question != null)
{
questionLabel.setText(question.getQuestion().getValue());
typeLabel.setText(question.getTypeReponse().getValue());
nbLigneLabel.setText(Integer.toString(question.getNbLignesReponse().getValue()));
reponseTable.setItems(FXCollections.emptyObservableList());
showReponseTable(question);
}else
{
questionLabel.setText("");
typeLabel.setText("");
nbLigneLabel.setText("0");
reponseTable.setVisible(false);
}
}
public void handleDelete()
{
int selectedIndex = questionTable.getSelectionModel().getSelectedIndex();
if(selectedIndex>=0)
{
questionTable.getItems().remove(selectedIndex);
}else
{
Alert alert = new Alert(AlertType.ERROR);
alert.initOwner(mainApp.getPrimaryStage());
alert.setTitle("Aucune question séléctionnée !");
alert.setContentText("Veuillez séléctionner une question valide !");
alert.showAndWait();
}
}
public void handleSave() throws IOException
{
FileChooser fileChooser = new FileChooser();
//Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("CTRL Files (*.ctrl)", "*.ctrl");
fileChooser.getExtensionFilters().add(extFilter);
//Show save file dialog
File file = fileChooser.showSaveDialog(this.mainApp.getPrimaryStage());
if(file != null){
FileOutputStream fout = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fout);
ArrayList<QuestionSerializable> qs = new ArrayList<QuestionSerializable>();
for(QuestionModel qm : this.mainApp.getQuestionData())
{
qs.add( new QuestionSerializable(qm));
}
oos.writeObject(new ArrayList<QuestionModel>(this.mainApp.getQuestionData()));
oos.close();
fout.close();
}
}
@SuppressWarnings("unchecked")
public void handleLoad() throws Exception
{
FileChooser fileChooser = new FileChooser();
//Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("CTRL Files (*.ctrl)", "*.ctrl");
fileChooser.getExtensionFilters().add(extFilter);
//Show save file dialog
File file = fileChooser.showSaveDialog(this.mainApp.getPrimaryStage());
if(file != null){
FileInputStream fout = new FileInputStream(file);
ObjectInputStream oos = new ObjectInputStream(fout);
ArrayList<QuestionSerializable> qm = (ArrayList<QuestionSerializable>) oos.readObject();
ObservableList<QuestionModel> qo = FXCollections.emptyObservableList();
for(QuestionSerializable q : qm)
{
qo.add(q.convert());
}
this.mainApp.setQuestionData(qo);
this.questionTable.refresh();
this.showQuestionDetails(null);
oos.close();
fout.close();
}
}
public void handleNew()
{
QuestionModel tempQuestion = new QuestionModel("");
tempQuestion.getReponseData().getValue().add(new SimpleStringProperty(""));
boolean okClicked = mainApp.showPersonEditDialog(tempQuestion);
if (okClicked) {
mainApp.getQuestionData().add(tempQuestion);
}
}
public void handleEdit()
{
QuestionModel selectedQuestion = questionTable.getSelectionModel().getSelectedItem();
if(selectedQuestion!=null)
{
boolean okClicked = mainApp.showPersonEditDialog(selectedQuestion);
if (okClicked) {
showQuestionDetails(selectedQuestion);
this.reponseTable.refresh();
}
}else
{
Alert alert = new Alert(AlertType.ERROR);
alert.initOwner(mainApp.getPrimaryStage());
alert.setTitle("Aucune question séléctionnée !");
alert.setContentText("Veuillez séléctionner une question valide !");
alert.showAndWait();
}
}
}
And line 172 is :
ObservableList<QuestionModel> qo = FXCollections.emptyObservableList();
for(QuestionSerializable q : qm)
{
qo.add(q.convert());
}
QuestionModelClass :
package model;
import java.io.Serializable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class QuestionModel{
private final StringProperty question;
private final StringProperty typeReponse = new SimpleStringProperty("Remplir Ligne");
private final IntegerProperty nbLignesReponse = new SimpleIntegerProperty(1);
private ObjectProperty<ObservableList<StringProperty>> reponseData = new SimpleObjectProperty<ObservableList<StringProperty>>(FXCollections.observableArrayList());
/**
* @return the reponseData
*/
public ObjectProperty<ObservableList<StringProperty>> getReponseData() {
return reponseData;
}
public void setReponseData(ObjectProperty<ObservableList<StringProperty>> reponseData)
{
this.reponseData = reponseData;
}
public QuestionModel(String question)
{
this.question = new SimpleStringProperty(question);
}
/**
* @return the nbLignesReponse
*/
public IntegerProperty getNbLignesReponse() {
return nbLignesReponse;
}
/**
* @return the question
*/
public StringProperty getQuestion() {
return question;
}
/**
* @return the typeReponse
*/
public StringProperty getTypeReponse() {
return typeReponse;
}
}
FXCollections.emptyObservableList()
returns a unmodifiable empty ObservableList
, which is why you get the UnsupportedOperationException
when you call add
.
Use FXCollections.observableArrayList()
to create the list instead:
ObservableList<QuestionModel> qo = FXCollections.observableArrayList();
This creates a list that can be modified. This list is initially empty.
Apparently the reponseData
and qm.getReponseData().getValue()
should have a type of ObjectProperty<List<StringProperty>>
.
The FXCollections documentation specifies that the method
FXCollections.emptyObservableList()
will return an "empty unmodifiable observable list".
Therefore, the loop
for(QuestionSerializable q : qm)
{
qo.add(q.convert());
}
will throw an UnsupportedOperationException
, since the qo
object is created by calling the aforementioned method.
To get a modifiable empty list, the method
FXCollections.observableArrayList()
should be called, as per the above documentation and fabian's earlier answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With