Here's some code that catches an exception thrown on the Event Dispatch Thread:
package com.ndh.swingjunk;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class EntryPoint {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
// System.setProperty("sun.awt.exception.handler", MyExceptionHandler.class.getName());
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new SomeWindow("foo").setVisible(true);
}
});
}
}
class SomeWindow extends JFrame {
public SomeWindow(String title) {
this.setTitle(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
throw new RuntimeException("hello");
}
}
I've seen warnings that exceptions thrown on the Event Dispatch Thread don't get handled by the UncaughtExceptionHandler, but that doesn't seem to be the case for my example; it works the same whether the registration line is commented out or left in. Is my example messed up somehow, or is registering the exception handler with the sun.awt.exception.handler no longer necessary?
The EDT class (java.awt.EventDispatchThread, don't look for it in the javadoc, this class is package private) has changed a lot since the origins of AWT.
In JDK6, you can see that this class now can properly handle exceptions occuring inside the EDT. Exception handling is a bit complex in the current version:
if you have set the
sun.awt.exception.handler property,
then your handler will be called for
every exception thrown by developer's
code called inside the EDT
(compatibility with previous JDK
versions is ensured).
otherwise, any exception will be
rethrown, hence will stop the current EDT, and any default
UncaughtExceptionHandler will be
able to catch it, as your snippet
demonstrates.
BUT (and this is very important), if you carefully look at the code of EDT, you'll see that this mechanism won't work if the exception occurs in the EDT while a modal dialog is displayed (I guess this is because EDT and EventQueue management is quite complicated and I would even dare say "messy": a lot of code looks like hacks in there).
In this exact situation, exceptions will be logged to System.err, except if you have set the sun.awt.exception.handler property. Having a default UncaughtExceptionHandler will not help.
So my take on this is that, YES, you should still bother with sun.awt.exception.handler property, except if you can say for sure that your application doesn't use modal dialogs (don't forget that JOptionPane dialogs are also modal).
You've called setDefaultUncaughtExceptionHandler instead of setUncaughtExceptionHandler. (If a SecurityManager is present: the former requires RuntimePermission setDefaultUncaughtExceptionHandler; the latter as SecurityManager.checkAccess(Thread).)
Related
We have a desktop Swing application with Google Guice 4.1.0 dependency injection. Everything worked fine during development, but something strange happened when colleague tried to run the application.
We have a MainWindow class that extends JPanel. In the constructor this class takes some controllers that itself are injectable. In main method Guice injector is created. Then the injector tries to instantiate MainWindow (injector.getInstance(MainWindow.class)). And it failed with NullPointerException!
This doesn't happen on my computer, and we use the same JDK.
Here is MainWindow class stripped down to problematic code (note: this does not reproduce the problem, unfortunately):
class MainWindow extends JPanel {
private final Foo foo;
private final JFrame frame;
#Inject
public MainWindow(Foo foo) {
super(new GridBagLayout()); // <-- NullPointerException
this.foo = foo;
this.frame = new JFrame("title");
}
public void createAndShowGUI() {
// ...
frame.add(this);
frame.pack();
frame.setVisible(true);
}
}
And here is main() method:
class Main {
private static final Injector injector = Guice.createInjector();
public static void main(String[] args) {
MainWindow mainWindow = injector.getInstance(MainWindow.class);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
mainWindow.createAndShowGUI();
}
});
}
}
Here is stack trace of the exception:
com.google.inject.ProvisionException: Unable to provision, see the following errors:
1) Error injecting constructor, java.lang.NullPointerException
at app.gui.MainWindow.<init>(MainWindow.java:133)
while locating app.gui.MainWindow
1 error
at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1028) ~[app-1.0-SNAPSHOT.jar:?]
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main.createAndShowGUI(Main.java:40) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main.access$000(Main.java:26) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main$2.run(Main.java:67) ~[app-1.0-SNAPSHOT.jar:?]
The NPE was thrown in the most surprising place – in the call to constructor of superclass of MainWindow (this is line 133). I started digging and found out that manual creation of MainWindow and injecting its dependencies works correctly:
MainWindow mainWindow = new MainWindow(injector.getInstance(Foo.class));
I suspected that maybe class loader didn't work correctly, so I tried again with logging classloader of both MainWindow and JPanel:
System.out.println("MainWindow: " + MainWindow.class.getClassLoader());
System.out.println("JPanel: " + JPanel.class.getClassLoader());
MainWindow mainWindow = injector.getInstance(MainWindow.class);
Class loaders are different (JPanel is loaded by bootstrap), but now the injection worked properly. I suppose this is because now JPanel class was explicitly loaded into main method context.
So my questions are:
Did anyone have similar problem?
Is it my mistake, or is it a bug?
If it is a bug, does it happen in Guice? Or maybe JRE?
More details about Java and OS:
I originally developed it with JDK 1.8.0u111, but then switched to JDK 1.8.0u121.
Application is compiled to Java 6.
Runs flawlessly on my computer with Windows 10, version 1607 (OS Build 14393.693), on JRE 6 and JRE 8 (from JDK).
NullPointerException is raised on colleague's computer with Windows 10, version 1511 (OS Build 10586.753), JDK 1.8.0u112 and 1.8.0u121.
Unfortunately I was unable to provide minimal version that reproduces the problem. Heck, I cannot even reproduce the problem, it happens only on colleague's environment.
I highly suspect this is due to a race condition. Swing components are not thread safe and should be instantiated on the EDT as per the swing package javadoc :
Swing's Threading Policy
In general Swing is not thread safe. All Swing components and related
classes, unless otherwise documented, must be accessed on the event
dispatching thread. Typical Swing applications do processing in
response to an event generated from a user gesture. For example,
clicking on a JButton notifies all ActionListeners added to the
JButton. As all events generated from a user gesture are dispatched on
the event dispatching thread, most developers are not impacted by the
restriction.
Where the impact lies, however, is in constructing and showing a Swing
application. Calls to an application's main method, or methods in
Applet, are not invoked on the event dispatching thread. As such, care
must be taken to transfer control to the event dispatching thread when
constructing and showing an application or applet. The preferred way
to transfer control and begin working with Swing is to use
invokeLater. The invokeLater method schedules a Runnable to be
processed on the event dispatching thread.
(emphasis mine)
Now you do start the UI in the EDT, using invokeLater, however you construct the UI on the main thread (through a Guice injector call).
The Guice injector call should also be in the invokeLater part to kick off the UI.
So I have some code that's throwing a RuntimeException. I know it's throwing a RuntimeException, I wrote it to do so under certain circumstances. Recently, I was having what I thought was a deadlock, because the method didn't seem to be finishing, but as I logged out the problem I realized that it was in fact that RuntimeException.
Now, here's the issue: This exception is occurring silently. The Android monitor in Android Studio isn't displaying a stack trace for it. This threw me off, because in normal Java applications (which I'm more used to, I'm a professional Java dev but I'm a bit new to Android), RuntimeExceptions send a stack trace directly to the console.
So, my reaction was to do a Thread.UncaughtExceptionHandler to log this. Only... it's not working.
Here's my UncaughtExceptionHandler. I don't actually care about it doing all the things it does, I was just trying to get something to happen to indicate that it was being called.
public static class ContactsUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
private static final String TAG = "UncaughtException";
#Override
public void uncaughtException(Thread thread, Throwable throwable) {
System.out.println("UNCAUGHT EXCEPTION"); //TODO delete this
Log.e(TAG, String.format("Uncaught exception in thread %d", thread.getId()), throwable);
throwable.printStackTrace();
System.exit(1);
}
}
This handler is being added in the following ways:
1) I have an executor spawning threads. It uses a ThreadFactory, which assigns this handler to each thread using Thread.setUncaughtExceptionHandler().
2) I call Thread.setDefaultUncaughtExceptionHandler() in the onCreate() method of my Application class.
3) The code where this is occurring is a Runnable.run() method. I put a line in that run() method calling Thread.currentThread().setUncaughtExceptionHandler().
Nothing works. None of those operations there get triggered.
I know with 100% certainty that a RuntimeException is occurring, because if I surround the code with a try-catch block and do printStackTrace() that way, it shows up in the console log. I just can't get the UncaughtExceptionHandler to work.
The code where this is happening is very long and verbose, here's a quick summary of it:
#Override
public void run(){
Thread.currentThread().setUncaughtExceptionHandler(new ContactsThreadFactory.ContactsUncaughtExceptionHandler());
System.out.println("This line outputs to the console");
object.callingMethodThatCausesException();
System.out.println("This line never executes, because exception was thrown");
}
Any ideas on how to fix this? I don't understand why it's not working.
Edit: Just discovered something interesting, not 100% sure what it means yet. I put "throws new RuntimeException()" into the onCreate() method of my Activity class, and that exception showed up in the console like normal. I tried doing the same thing from within that Runnable, and nothing. Not entirely sure what to make of that.
Also, the UncaughtExceptionHandler worked for that new RuntimeException I put in. I just don't understand why it's not working elsewhere?
I am developing a Swing application with a component performing custom painting. When I make some mistake in the painting code and an exception is thrown, the situation is hard to debug. Instead of being caught by the debugger, a popup shows with the exception information. Moreover, the thread seems to be restarted, and as the exception is a result of coding error, it is shown again and again.
When I am lucky enough to switch into the debugger (which is difficult, because more and more popups keep coming as the application gets paint requests), the debugging console shows me an exception information like:
SEVERE: Uncaught exception thrown in Thread[AWT-EventQueue-0,6,main]
.... stack follows
My application is written in Scala and I am using IntelliJ IDEA 14. My uncaught main thread exceptions are handled fine by the debugger (I have Uncaught exception enabled for Any exception breakpoint enabled in the Java Exception Breakpoints), but exceptions in AWT threads are not.
I have tried installing a handler as described in this How can I detect when an Exception's been thrown globally in Java? answer, but my handler does not seem to be triggered.
I would like to achieve following (in order of importance):
avoid the AWT thread restarting on exception, or at least prevent the popup from showing
handle uncaught exceptions in the debugger instead of being printed in the console
(Note: while this is Scala application, I assume the behaviour would be the same for Java, hence the Java tag).
According to this link, you have to handle both regular Exception and EDT Exception without using the old sun.awt.exception.handler hack (which does not work anymore since Java 7)
Here is your ExceptionHandler
public static class ExceptionHandler implements Thread.UncaughtExceptionHandler
{
public void uncaughtException(Thread thread, Throwable thrown)
{
// TODO handle your Exception here
}
}
Usage :
// 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());
}
});
In Java
Your problem is that the exception is being thrown in another thread, the event dispatch thread. A couple of solutions:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
logger.error("Uncaught exception in thread: " + t.getName, e);
}
});
In any case you should in principle but your UI startup code in a
EventQueue.invokeLater();
or SwingUtilities.invokeLater() that directly call this.
In Scala
Your problem is that the exception is being thrown in another thread, the event dispatch thread. A couple of solutions:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
def uncaughtException(t: Thread, e: Throwable) {
logger.error("Uncaught exception in thread: " + t.getName, e)
}
})
In any case you should in principle but your UI startup code in a
EventQueue.invokeLater()
Looks like your only solution might be switching to Eclipse. :-) The other solutions require coding effort and stopping in the exception handler is not the same as stopping in the exact place where the exception is thrown.
With the following program I have no problems listening to caught/uncaught instances of RuntimeException in Eclipse.
package lambda;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class AWTExceptionTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Test");
button.addActionListener(e -> { throw new RuntimeException(); });
frame.add(button);
frame.setSize(new Dimension(50, 50));
SwingUtilities.invokeLater(() -> frame.setVisible(true));
}
}
Here is how it looks in debug mode in Eclipse.
How can I detect when an Exception has been thrown anywhere in my application?
I'm try to auto-magically send myself an email whenever an exception is thrown anywhere in my Java Desktop Application. I figure this way I can be more proactive.
I know I could just explicitly log and notify myself whenever an exception occurs, but I'd have to do it everywhere and I might(more likely will) miss a couple.
Any suggestions?
You probobly don't want to mail on any exception. There are lots of code in the JDK that actaully depend on exceptions to work normally. What I presume you are more inerested in are uncaught exceptions. If you are catching the exceptions you should handle notifications there.
In a desktop app there are two places to worry about this, in the event-dispatch-thread (EDT) and outside of the EDT. Globaly you can register a class implementing java.util.Thread.UncaughtExceptionHandler and register it via java.util.Thread.setDefaultUncaughtExceptionHandler. This will get called if an exception winds down to the bottom of the stack and the thread hasn't had a handler set on the current thread instance on the thread or the ThreadGroup.
The EDT has a different hook for handling exceptions. A system property 'sun.awt.exception.handler' needs to be registerd with the Fully Qualified Class Name of a class with a zero argument constructor. This class needs an instance method handle(Throwable) that does your work. The return type doesn't matter, and since a new instance is created every time, don't count on keeping state.
So if you don't care what thread the exception occurred in a sample may look like this:
class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
handle(e);
}
public void handle(Throwable throwable) {
try {
// insert your e-mail code here
} catch (Throwable t) {
// don't let the exception get thrown out, will cause infinite looping!
}
}
public static void registerExceptionHandler() {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
}
}
Add this class into some random package, and then call the registerExceptionHandler method and you should be ready to go.
The new debugging hooks in Java 1.5 let you do this. It enables e.g. "break on any exception" in debuggers.
Here's the specific Javadoc you need.
Check out Thread.UncaughtExceptionHandler. You can set it per thread or a default one for the entire VM.
This would at least help you catch the ones you miss.
If you're using a web framework such as Spring then you can delegate in your web.xml to a page and then use the controller to send the email. For example:
In web.xml:
<error-page>
<error-code>500</error-code>
<location>/error/500.htm</location>
</error-page>
Then define /error/500.htm as a controller. You can access the exception from the parameter javax.servlet.error.exception:
Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
If you're just running a regular Java program, then I would imagine you're stuck with public static void main(String[] args) { try { ... } catch (Exception e) {} }
If you are using java 1.3/1.4, Thread.UncaughtExceptionHandler is not available.
In this case you can use a solution based on AOP to trigger some code when an exception is thrown. Spring and/or aspectJ might be helpful.
In my current project I faced the similar requirement regarding the errors detection. For this purpose I have applied the following approach: I use log4j for logging across my app, and everywhere, where the exception is caught I do the standard thing: log.error("Error's description goes here", e);, where e is the Exception being thrown (see log4j documentation for details regarding the initialization of the "log").
In order to detect the error, I use my own Appender, which extends the log4j AppenderSkeleton class:
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class ErrorsDetectingAppender extends AppenderSkeleton {
private static boolean errorsOccured = false;
public static boolean errorsOccured() {
return errorsOccured;
}
public ErrorsDetectingAppender() {
super();
}
#Override
public void close() {
// TODO Auto-generated method stub
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
protected void append(LoggingEvent event) {
if (event.getLevel().toString().toLowerCase().equals("error")) {
System.out.println("-----------------Errors detected");
this.errorsOccured = true;
}
}
}
The log4j configuration file has to just contain a definition of the new appender and its attachement to the selected logger (root in my case):
log4j.rootLogger = OTHER_APPENDERS, ED
log4j.appender.ED=com.your.package.ErrorsDetectingAppender
You can either call the errorsOccured() method of the ErrorsDetectingAppender at some significant point in your programs's execution flow or react immidiately by adding functionality to the if block in the append() method. This approach is consistent with the semantics: things that you consider errors and log them as such, are detected. If you will later consider selected errors not so important, you just change the logging level to log.warn() and report will not be sent.
In this case I think your best bet might be to write a custom classloader to handle all classloading in your application, and whenever an exception class is requested you return a class that wraps the requested exception class. This wrapper calls through to the wrapped exception but also logs the exception event.
I assume you don't mean any Exception but rather any uncaught Exception.
If this is the case this article on the Sun Website has some ideas. You need to wrap your top level method in a try-catch block and also do some extra work to handle other Threads.
Sending an email may not be possible if you are getting a runtime exception like OutOfMemoryError or StackOverflow. Most likely you will have to spawn another process and catch any exceptions thrown by it (with the various techniques mentioned above).
There is simply no good reason to be informed of every thrown exception. I guess you are assuming that a thrown exception indicates a "problem" that your "need" to know about. But this is wrong. If an exception is thrown, caught and handled, all is well. The only thing you need to be worried about is an exception that is thrown but not handled (not caught). But you can do that in a try...catch clause yourself.
I'm trying to create my own dialog by extending the JDialog class
this is the code i used to start:
import javax.swing.JDialog;
public class ColorManager extends JDialog {
private static final long serialVersionUID = 1L;
public ColorManager(){
super();
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.pack();
this.setVisible(true);
}
}
when i try to run the code it works fine but i'm getting the following exception:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: defaultCloseOperation must be one of: DO_NOTHING_ON_CLOSE, HIDE_ON_CLOSE, or DISPOSE_ON_CLOSE
i read that there were problems with WINDOWS_EXIT or something like that but the parameter i pass should do the job.
the thing that makes it even weirder is that when i change my class so it will contain a JDialog field instead of extending it, it seems to work just fine.
I asked a friend to test this on his computer and the code did not throw the exception, he is using jre version 1.6.022 and I'm using 1.6.022 both of us are using 64 bit.
so what did i do wrong? or is that a bug in the JRE?
Edit: forgot to mention, I'm using eclipse
Edit2: i tried the same code in Netbeans and it works fine, what could be my problem??
All the methods you call in constructor should be called on the EDT thread. It is not advised to do it inside the constructor, but if you insist make sure it runs on Swing (EDT) thread such as:
import javax.swing.JDialog;
public class ColorManager extends JDialog {
private static final long serialVersionUID = 1L;
public ColorManager(){
super();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.pack();
this.setVisible(true);
}
});
}
}
IMO the best way do accomplish it would be to move this into separate method and then call it after creating your ColorManager instance.
When using Swing you should always adhere to Swing threading rules. More information can be found at
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
All the above solution are great, I also had very disturbing moment with show the JDialog.
On NETBEAN 8.2 just left click the JFrame and choose properties, then set the defaultCloseOperation Property ... Usually the first on the list,
do the same for the JDialog
... Anyway that,s my own experience