Catch exceptions in javax.swing application - java

I'm working with javax.swing to make an aplication which generates forms from XML Schema (using JAXFront library) and stores the data filled by the user them into XML documents.
I have put try-catch-finally blocks when I need it, but I have a little problem catching exceptions when the main thread ends (The AWT threads are still running).
I have two classes which do the main work and other classes which aren't important for the question:
Main class: It has the following structure. Initializes the application and runs the main frame
public class Main {
public static void main(String[] args) {
readArgs(); // An INI file with the app config
Model model = initializeElements(args); // My model class
try {
MyFrame mfr = new MyFrame(title,model);
mfr.visualize(); // Assembling view and setting visible
} catch( Excepion e ) {
doCleanUp();
System.exit(-1);
}
}
}
Frame Class: Generates the view and listen events
public class MyFrame extends JFrame implements ActionListener,MenuListener {
// Some attributes
// Other mthods without importance
/**
* Compose the elements, add listeners and set visible the frame
*/
public void visualize() {
generateFormPanel();
setListeners();
validate();
setVisible(true);
}
public MyFrame(String title, Modele model) {
super(title);
createElementsUsing(model);
}
public void actionPerformed(ActionEvent e) {
// Code to manage events
}
}
Well, the problem is the following:
When the visualize function is exectuted from the main method, the view is generated and showed. At that moment is when I lose the control of the exceptions catching. Then my question is if there are some way to catch the possible RuntimeExceptions throwed after this point.
I hope you understand my English and can answer the question.
Thanks in advance.

Simplest version is to set the default uncaught exception handler:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
// do something
}
});
But that catches uncaught exceptions thrown in other parts of the program aswell.
You could however catch only runtime exceptions thrown off the swing event dispatching thread using a proxy (See this page for more information, copied code from there):
class EventQueueProxy extends EventQueue {
protected void dispatchEvent(AWTEvent newEvent) {
try {
super.dispatchEvent(newEvent);
} catch (Throwable t) {
// do something more useful than: t.printStackTrace();
}
}
}
Now installing it like this:
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueueProxy());

After you have called visualize() the only thread running is the Swing/AWT event dispatch thread. If you want to catch any exceptions you will need to do so in any of your listener methods that are called on this thread e.g.
public void actionPerformed(ActionEvent e) {
try {
// Some code here
} catch(RuntimeException e) {
// Handling code here
}
}
To prevent boilerplate you can have this code in a super class.
Note that you can also set a default uncaught exception handler if you want to catch anything not already dealt with by the Swing/AWT thread.
Note also that in general it is best practice to not catch subclasses of RuntimeException if you can avoid it.

Try adding:
setDefaultCloseOperation(EXIT_ON_CLOSE);
to MyFrame constructor. Not sure though, but worth trying.

Related

StreamResourceWriter error handling via ErrorHandler interface

I have a FileCreator class that implements StreamResourceWriter interface and MainErrorHandler class that implements ErrorHandler. I'm using the MainErrorHandler class as a centralized Exception handler in my project which mostly logs the exception and shows a notification to the user. The problem is that StreamResourceWriter.accept() method runs in a non UI thread and when an Exception is thrown it is directed to the ErrorHandler which then fails to show a notification due to "IllegalStateException: UI instance is not available". Is there a way to show a notification window to the user from MainErrorHandler when FileCreator throws an error in accept() method?
Below FileCreator snippet.
public class FileCreator implements StreamResourceWriter {
#Override
public void accept(OutputStream stream, VaadinSession session) throws IOException {
// Run in a non ui thread.
// Writes to OutputStream but an Exception might be thrown during this process
}
}
Below MainErrorHandler snippet.
/**
* Centralized error handler
*/
public class MainErrorHandler implements ErrorHandler {
private static final Logger log = LoggerFactory.getLogger(MainErrorHandler.class);
#Override
public void error(ErrorEvent event) {
log.error("Error occurred", event.getThrowable());
//Cannot show a notification if ErrorEvent came from FileCreator.
//Will get an IllegalStateException: UI instance is not available.
Notification.show("Error occurred");
//Tried UI.getCurrent but it returns null if ErrorEvent came from FileCreator.
UI.getCurrent();
}
}
Using Vaadin 13.0.1.
Edit
One way to solve this issue is to pass UI reference to FileCreator directly. Below an example.
public class FileCreator implements StreamResourceWriter {
private UI ui;
//Pass UI reference directly
public FileCreator(UI ui){
this.ui = ui;
}
#Override
public void accept(OutputStream stream, VaadinSession session) throws IOException {
try{
// Run in a non ui thread.
// Writes to OutputStream but an Exception might be thrown during this process
}catch(Exception e){
//I don't like this since have to catch all exceptions and have to call ErrorHandeler directly with a UI reference. Also what if somewhere in code ErrorHandler is changed and is not of type MainErrorHandler.
((MainErrorHandler)VaadinSession.getCurrent().getErrorHandler()).error(e, ui);
}
}
}
As I said in comments I really don't like this approach either since I am forced to catch all Exceptions, have to cast ErrorHandler to MainErrorHandler and calling it directly.
There is a way, but it's not perfect.
You can get all UI instances via VaadinSession.getCurrent().getUIs().
To filter out the inactive/detached UIs you can check if ui.getSession() returns a VaadinSession (so, not null). The JavaDoc of getSession says:
The method will return null if the UI is not currently attached to a VaadinSession.
Then you can invoke the access method on each of the UIs and create and show the notification inside the UI-context.
for(UI ui : VaadinSession.getCurrent().getUIs()) {
// Filtering out detached/inactive UIs
if (ui.getSession() != null) {
ui.access(() -> {
// create Notification here
});
}
I said it's not perfect because you have to keep in mind that the user can have several UIs opened at the same time(e.g. multiple tabs).

Java convert from one exception to another

I have a common project with some shared code that is being used in another project. I'm trying to convert/map the exception from the common project CommonException to a new type of Exception let's call it SuperAwesomeException.
The aim is to have a generic way of handling all custom exceptions in the project.
I've attempted to do this using an UncaughtExceptionHandler. This seems to work when running the project but not from within JUnit, since that wraps each test in a try/catch block as described here.
public final class ExceptionHandler implements Thread.UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread thread, Throwable exception) {
if (exception instanceof CommonException) {
throw new SuperAwesomeException(exception.getMessage());
}
if (exception instanceof SuperAwesomeException) {
throw new CommonException(exception.getMessage());
}
else {
System.out.println("ERROR! caught some other exception I don't really care about");
System.out.println("Not doing anything");
}
}
}
Is there another way I can map from one Exception to another or can I somehow tell JUnit not to catch certain exceptions and check the Exception is mapped to the correct one?
UPDATE - How I initially tried to write the Test:
public class ClassThatThrowsException {
ClassThatThrowsException() {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
}
public void doSomething() {
throw new CommonException("Something boring blew up!");
}
}
public class ClassThatThrowsExceptionTest {
#Test(expected=SuperAwesomeException.class)
public void testAwesome() {
ClassThatThrowsException c = new ClassThatThrowsException();
c.doSomething();
}
}
which throws:
java.lang.Exception: Unexpected exception, expected<SuperAwesomeException> but was<CommonException>
The problem is: when you are using JUnit, the framework will catch your exception. Therefore the uncaught exception handler isn't called in the first place!
See here for more details.
Thus, you have to do two things:
A) write tests that make sure that your exception handler implementation works as desired
#Test(expected=SuperAwesomeException.class)
public void testAwesome() {
new ExceptionHandler().uncaughtException(null, new CommonException("whatever"));
}
B) thest the plumbing - you want to make sure that this specific uncaught handler gets actually set by your code:
#Test
public void testDefaultHandlerIsSet() {
// creating a new instance should update the handler!
new ClassThatThrowsException();
Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
assertThat(handler, not(nullValue()));
assertThat(handler, instanceOf(ExceptionHandler.class));
}
Finally - please note: you should not just do new XException(oldException.getMessage). Rather go for new XException("some message, oldException).
In other words: you got a cause here; so you better use the incoming exception as cause within the new one you intend to throw. Otherwise you loose all stack trace information.

about override run() method of GUI in main method

The issue is when I close my GUI windows I wanna run a last method ( for example printList() ) but I couldn't manage to do it. This is my main method
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
patientTest2 screen = new patientTest2();
screen.setVisible(true);
screen.setResizable(false);
} catch (FileNotFoundException ex) {
Logger.getLogger(patientTest2.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
patientTest2 is my JFrame class. I assume that if I put printList() before } catch (FileNotFoundException ex) { it should work and finally print my list to a file but it doesn't. I will be glad if you can help me and explain why of course_?
You should add a listener that extends WindowAdapter to your frame, and override the method windowClosing(WindowEvent e). In this method, you will be able to call any methods you want to call before the window is closed.
You need to
change the default close operation to JFrame.DO_NOTHING_ON_CLOSE (if the window is a JFrame)
add a WindowListener to your top-level window
listen for window closing events, calling your method
and then finally exit the JVM with the appropriate exit code (usually 0 if no errors).
If you want to have something that runs when you Java VM gets shut down, then you should have a look at
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
#Override
public void run() {
//The stuff you want to do at shutdown.
}
}));
Please read the here for further information.
You also should set the DefaultCloseOperation of your Window if you want to close your Programm (and shutdown your Java VM) when the JFrame is closed.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
This is I think what you were asking for. Hope this helps.

How to run code after a call to Sytem.exit(0) in a finally block

I have three classes say alpha, beta, gamma and each of the three classes has a main method.
Both alpha and beta classes have, inside their main method, a try...catch...finally block like:
public class alpha{
public static void main(String[] args){
try{
Do something;
}catch(Exception ex){
ex.printStackTrace();
}
finally{
System.exit(0);
}
}
}
public class beta{
public static void main(String[] args){
try{
Do something;
}catch(Exception ex){
ex.printStackTrace();
}
finally{
System.exit(0);
}
}
}
Now in gamma class i call main methods of alpha and beta classes to run continuously like below
public gamma{
public static void main(String[] args) {
try {
alpha.main(arg);
beta.main(arg1);
} catch (Exception e) {
e.printStackTrace();
}
}
The problem is that the code beta.main(arg1) is never reached due to the System.exit(0) inside the alpha class's finally block.
Since alpha and beta are standalone applications when they executed separately they should terminate the service at the end of program.
So now this there any way to reach the beta.main(arg1) line without much changing the actual functionality of alpha and beta classes.
Kindly let me know if you need further details.
Thanks in advance...
In such case, shutdown hook can be used:
public class Gamma{
public static void main(String[] args) {
try {
Thread hook = new Thread() { public void run() { Beta.main(args); } };
hook.setDaemon(true);
Runtime.getRuntime().addShutdownHook(hook);
Alpha.main(args);
} catch (Exception e) {
e.printStackTrace();
}
}
}
(Ideally, nothing that is part of a module's public API should ever do anything that calls exit, and the main method of a class should just be a small shim that invokes something else that does the real work before producing the proper exit code.)
That said, if you want to prevent System.exit, you can register a SecurityManager that converts calls to System.exit into SecurityExceptions or Errors.
System.exit:
throws
SecurityException - if a security manager exists and its checkExit method doesn't allow exit with the specified status.
Something like
System.setSecurityManager(new SecurityManager() {
#Override
public void checkExit(int exitCode) throws SecurityException {
throw new SecurityException("stop that");
}
});
Then the method which is calling main methods can just catch and suppress that SecurityException. You could make it more robust by creating your own ExitCalledError and throwing that instead and only suppressing that.
I find this very useful for preventing unit-test runners from spuriously reporting success when the test runner is exited by code under test with a zero exit code.
Really, the only solution is to get rid of the System.exit() call. This is why System.exit() is evil. A good way to replace them is by throwing an exception -- you can add an exception handler to the system (look into adding them to ThreadGroups to add one for every exception path) and then decide what you want to do.
System.exit(0) terminates the currently running Java Virtual Machine. It closes all application on the VM, not just the application which calls System.exit(0). You need to think alternative for your functionality. Here is a link about it. System.exit usage

How can I catch AWT thread exceptions in Java?

We'd like a trace in our application logs of these exceptions - by default Java just outputs them to the console.
Since Java 7, you have to do it differently as the sun.awt.exception.handler hack does not work anymore.
Here is the solution (from Uncaught AWT Exceptions in Java 7).
// Regular Exception
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
// EDT Exception
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
// We are in the event dispatching thread
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
}
});
There is a distinction between uncaught exceptions in the EDT and outside the EDT.
Another question has a solution for both but if you want just the EDT portion chewed up...
class AWTExceptionHandler {
public void handle(Throwable t) {
try {
// insert your exception handling code here
// or do nothing to make it go away
} catch (Throwable t) {
// don't let the exception get thrown out, will cause infinite looping!
}
}
public static void registerExceptionHandler() {
System.setProperty('sun.awt.exception.handler', AWTExceptionHandler.class.getName())
}
}
A little addition to shemnons anwer:
The first time an uncaught RuntimeException (or Error) occurs in the EDT it is looking for the property "sun.awt.exception.handler" and tries to load the class associated with the property. EDT needs the Handler class to have a default constructor, otherwise the EDT will not use it.
If you need to bring a bit more dynamics into the handling story you are forced to do this with static operations, because the class is instantiated by the EDT and therefore has no chance to access other resources other than static. Here is the exception handler code from our Swing framework we are using. It was written for Java 1.4 and it worked quite fine there:
public class AwtExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(AwtExceptionHandler.class);
private static List exceptionHandlerList = new LinkedList();
/**
* WARNING: Don't change the signature of this method!
*/
public void handle(Throwable throwable) {
if (exceptionHandlerList.isEmpty()) {
LOGGER.error("Uncatched Throwable detected", throwable);
} else {
delegate(new ExceptionEvent(throwable));
}
}
private void delegate(ExceptionEvent event) {
for (Iterator handlerIterator = exceptionHandlerList.iterator(); handlerIterator.hasNext();) {
IExceptionHandler handler = (IExceptionHandler) handlerIterator.next();
try {
handler.handleException(event);
if (event.isConsumed()) {
break;
}
} catch (Throwable e) {
LOGGER.error("Error while running exception handler: " + handler, e);
}
}
}
public static void addErrorHandler(IExceptionHandler exceptionHandler) {
exceptionHandlerList.add(exceptionHandler);
}
public static void removeErrorHandler(IExceptionHandler exceptionHandler) {
exceptionHandlerList.remove(exceptionHandler);
}
}
Hope it helps.
There are two ways:
/* Install a Thread.UncaughtExceptionHandler on the EDT */
Set a system property:
System.setProperty("sun.awt.exception.handler",MyExceptionHandler.class.getName());
I don't know if the latter works on non-SUN jvms.
--
Indeed, the first is not correct, it's only a mechanism for detecting a crashed thread.

Categories

Resources