Given the controller of a Scene calls business code which raises an Exception. How can I handle those kind of Exceptions in a general fashion?
I tried the Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)
method but it is not invoked so I believe that the Exceptions are catched somewhere inside the JavaFX framework.
What could I do to handle this Exceptions or at least show some useful information to the user?
Best Answer
As of JavaFX 8,
Thread.setDefaultUncaughtExceptionHandler(...)
should work: see RT-15332.Things are a little complicated if an uncaught exception occurs during execution of the
start(...)
method. Depending on how the application is launched, the code that invokesstart()
(e.g. the implementation ofApplication.launch(...)
) may catch the exception and handle it, which would obviously prevent the default exception handler from being invoked.In particular, on my system (JDK 1.8.0_20 on Mac OS X 10.9.5), it appears that if my application starts up via a
main(...)
method that invokesApplication.launch(...)
, any exception thrown in thestart()
method is caught (and not rethrown).However, if I remove the
main(...)
method (see note below) and launch the application directly, any exception thrown in thestart()
method is rethrown, allowing the default exception handler to be invoked. Note that it doesn't merely propagate up.start()
is invoked on the FX Application Thread and the exception is rethrown from the main thread. Indeed, when this occurs, code in the default handler that assumes the FX Application Thread is running fails to run: so my guess is that the launching code in this case catches exceptions in thestart()
method, and in thecatch
block, shuts down theFX Application Thread
, and then rethrows the exception from the calling thread.The upshot of all this is that it is important - if you want your default handler to handle exceptions in the
start()
method, you should not call any UI code if the exception is not thrown on the FX Application Thread (even via aPlatform.runLater(...)
).Note: (for those who may not be aware of this). As of Java 8, you can directly launch an
Application
subclass even if it doesn't have amain(...)
method, by passing the classname as an argument to the JVM executable in the usual way (i.e.java MyApp
). This does what you'd expect: starts up the FX toolkit, starts the FX Application thread, instantiates theApplication
subclass and callsinit()
, then on the FX Application Thread callsstart()
. Interestingly (and perhaps incorrectly), amain(...)
method that invokesApplication.launch()
behaves slightly differently with respect to uncaught exceptions in thestart(...)
method.Here is a basic example. Uncomment the code in
Controller.initialize()
to see an exception thrown in thestart()
method.With Main.fxml:
Controller.java:
Error.fxml:
ErrorController.java: