I am learning JavaFX, and have hit a stumbling block with running a task. I have followed the progress of the task with the NetBeans debugger, and found that ConfigModelSansUpdateTask clearly runs.
When the application gets to the configModelWorkerSansUpdates.setOnSucceeded, somehow this result (stored in configModel) becomes null, throwing a NullPointerException.
Having read through the post on NullPointerException, I am none the wiser as to why the result of my Task is being being nulled. There is nothing obvious that does this, as I clearly get a result that then becomes null when I come to use it:
Snapshot of when the task is about to return a result:
And when I come to use the result:
Help!
SWMUApp.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package swmuapp;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import jaxb.TaskModel;
/**
*
* @author Shaun Connelly-Flynn
*/
public class SWMUApp extends Application {
public SWMUApp() {
}
@Override
public void start(Stage stage) throws Exception {
FXMLLoader centralSeceneLoader = new FXMLLoader(getClass().getResource("forms/CentralScene.fxml"));
Parent centralRoot = (Parent) centralSeceneLoader.load();
Scene scene = new Scene(centralRoot);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
CentralSceneController.java
package swmuapp.controllers;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.concurrent.WorkerStateEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Tab;
import jaxb.TaskModel;
import swmuapp.SWMUApp;
import swmuapp.init.ConfigModelWorkerSansUpdates;
import swmuapp.init.LocationModelWorker;
import swmuapp.models.ConfigModel;
import swmuapp.models.LocationModel;
/**
* FXML Controller class
*
* @author Shaun Connelly-Flynn
*/
public class CentralSceneController implements Initializable {
@FXML
private Tab sessionTab;
@FXML
private Tab tractionTab;
@FXML
private Tab locationTab;
@FXML
private Tab swmuTab;
@FXML
private Tab exportTab;
private final TaskModel taskModel;
// Models
private ConfigModel configModel;
private LocationModel locationModel;
// Child Controllers
@FXML
private ImportPaneController importPaneController;
@FXML
private SWMUPaneController swmuPaneController;
@FXML
private SessionPaneController sessionPaneController;
public CentralSceneController() {
this.taskModel = new TaskModel();
}
/**
* Initialises the controller class.
*
* @param url
* @param rb
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
// Give a reference of this controller to the child controllers
importPaneController.setParentController(this);
// Now subimt the configModel task
ConfigModelWorkerSansUpdates configModelWorkerSansUpdates = new ConfigModelWorkerSansUpdates(taskModel);
configModelWorkerSansUpdates.setOnSucceeded((WorkerStateEvent event) -> {
System.out.println(event.getEventType().toString());
// Get the location model
Future<LocationModel> locationFuture = taskModel.submitTask(new LocationModelWorker(configModel, taskModel));
try {
locationModel = locationFuture.get();
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(SWMUApp.class.getName()).log(Level.SEVERE, null, ex);
}
// Notify the controllers that we're ready
sessionPaneController.setConfigModel(configModel);
sessionPaneController.setLocationModel(locationModel);
});
configModelWorkerSansUpdates.setOnFailed(p -> System.out.println(p.toString()));
configModelWorkerSansUpdates.setOnCancelled(p -> System.out.println(p.toString()));
// Fetch the config model
Future<ConfigModel> configFuture = taskModel.submitTask(configModelWorkerSansUpdates);
try {
configModel = configFuture.get();
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(SWMUApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
TaskModel.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package jaxb;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javafx.concurrent.Task;
/**
*
* @author Shaun Connelly-Flynn
*/
public class TaskModel {
private final ExecutorService service;
public TaskModel() {
this.service = Executors.newCachedThreadPool();
}
public Future submitTask(Callable task) {
return service.submit(task);
}
public Future submitTask(Task task) {
return service.submit(task);
}
public List<Future> submitTasks(List<Callable> tasks) {
List<Future> futureList = new ArrayList<>();
for(Callable task : tasks) {
futureList.add(submitTask(task));
}
return futureList;
}
}
ConfigModelWorkerSansUpdates.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package swmuapp.init;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javafx.concurrent.Task;
import jaxb.Binder;
import jaxb.TaskModel;
import jaxb.bundles.QueryBundle;
import jaxb.bundles.ResultsBundle;
import jaxb.query.XQuery;
import swmuapp.config.jaxb.JaxbConfig;
import swmuapp.config.jaxb.JaxbDatabases;
import swmuapp.models.ConfigModel;
/**
*
* @author Shaun Connelly-Flynn
*/
public class ConfigModelWorkerSansUpdates extends Task<ConfigModel> {
private final TaskModel taskModel;
public ConfigModelWorkerSansUpdates(TaskModel taskModel) {
this.taskModel = taskModel;
}
@Override
protected ConfigModel call() throws Exception {
// Get the list of active databases
QueryBundle databaseBundle = new QueryBundle(
new XQuery("SWMUDB", "<databases>{databases/database}</databases>"),
JaxbDatabases.class,
"src/swmuapp/schema/DatabaseSchema.xsd");
// Now read the configuration
QueryBundle configBundle = new QueryBundle(
new XQuery("SWMUDB", "configs/config"),
JaxbConfig.class,
"src/swmuapp/schema/ConfigSchema.xsd");
// Submit the tasks
Future<ResultsBundle> dbTask = taskModel.submitTask(new Binder(databaseBundle, taskModel));
Future<ResultsBundle> configTask = taskModel.submitTask(new Binder(configBundle, taskModel));
// Create empty objects in case of failure!
JaxbDatabases dbResult = new JaxbDatabases();
JaxbConfig configResult = new JaxbConfig();
try {
// Now fetch the list of databases
dbResult = (JaxbDatabases) dbTask.get().getResult();
// Fetch the configuration
configResult = (JaxbConfig) configTask.get().getResult();
} catch (ExecutionException ex) {
setException(ex);
throw ex;
}
// Now put it all together
ConfigModel configModel = new ConfigModel(dbResult);
// And give it back!
return configModel;
}
}
SessionPaneController.java
package swmuapp.controllers;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.TableView;
import swmuapp.models.ConfigModel;
import swmuapp.models.LocationModel;
/**
* FXML Controller class
*
* @author Shaun Connelly-Flynn
*/
public class SessionPaneController implements Initializable {
@FXML
private ListView<String> dbListView;
@FXML
private TableView<?> detailedTableView;
private CentralSceneController controller;
private ConfigModel configModel;
private LocationModel locationModel;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
}
public void setConfigModel(ConfigModel configModel) {
if (this.configModel == null) {
this.configModel = configModel;
} else {
throw new IllegalArgumentException("SessionPaneController::setConfigModel -- config model already set!");
}
dbListView.setItems(configModel.getDatabases());
}
public void setLocationModel(LocationModel locationModel) {
this.locationModel = locationModel;
}
protected void setParentController(CentralSceneController controller) {
this.controller = controller;
}
}
Stack:
java.util.concurrent.ExecutionException: java.lang.NullPointerException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at swmuapp.controllers.CentralSceneController.lambda$initialize$0(CentralSceneController.java:84)
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:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.concurrent.EventHelper.fireEvent(EventHelper.java:219)
at javafx.concurrent.Task.fireEvent(Task.java:1356)
at javafx.concurrent.Task.setState(Task.java:723)
at javafx.concurrent.Task$TaskCallable.lambda$call$500(Task.java:1434)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
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(Thread.java:745)
Caused by: java.lang.NullPointerException
at swmuapp.init.LocationModelWorker.call(LocationModelWorker.java:35)
at swmuapp.init.LocationModelWorker.call(LocationModelWorker.java:22)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
... 1 more
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at swmuapp.controllers.SessionPaneController.setConfigModel(SessionPaneController.java:49)
at swmuapp.controllers.CentralSceneController.lambda$initialize$0(CentralSceneController.java:90)
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:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.concurrent.EventHelper.fireEvent(EventHelper.java:219)
at javafx.concurrent.Task.fireEvent(Task.java:1356)
at javafx.concurrent.Task.setState(Task.java:723)
at javafx.concurrent.Task$TaskCallable.lambda$call$500(Task.java:1434)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
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(Thread.java:745)

