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.
Related
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'm trying to write a unit test for my applications uncaught thread exception handler, but have had no luck so far. The handler is application wide, and I know it works. It was also based around code found here. However I can't think of a way to actually write a unit test for it, considering that if I throw an exception from my test project it is entering that code, but it never returns. This causes any test that I've so far written to fail out.
Here is my handler, does anyone have any suggestions how I can unit test this?
public class MyApplication extends Application {
// uncaught exception handler variable
private final UncaughtExceptionHandler defaultUEH;
// handler listener
private final Thread.UncaughtExceptionHandler _unCaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
// Try restarting the application if an uncaught exception has
// occurred.
PendingIntent myActivity = PendingIntent
.getActivity(getApplicationContext(), 192837, new Intent(
getApplicationContext(), MainGui.class), PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager;
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 15000, myActivity);
System.exit(2);
// re-throw critical exception further to the os (important)
defaultUEH.uncaughtException(thread, ex);
}
};
public MyApplication() {
defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
// setup handler for uncaught exception
Thread.setDefaultUncaughtExceptionHandler(_unCaughtExceptionHandler);
}
My project that contains the tests is separate from my actual application project. I've tried setting flags in the code, but after the exception is called, my test has already failed and there is no opportunity to check that flags have been set. I've thought of maybe adding a broadcast in the uncaught exception handler and triggering off that, or maybe to use preferences and somehow re-run the test to check the preference has changed, but that doesn't seam very reliable and I would like to avoid too much extra code that is just inserted for the sake of testing if that is possible.
Thanks!
I would guess that your test framework is catching all exceptions (junit does this), so the UncaughtExceptionHandler is never called.
However, if you run a test that starts a new Thread, the framework should not catch exceptions in that Thread. For example:
public void testUncaughtExceptionhandler()
{
Thread testThread = new Thread()
{
public void run()
{
throw new RuntimeException("Expected!");
}
};
testThread.start();
testThread.join();
}
That should successfully throw an exception that would be caught by the UncaughtExceptionHandler.
What this is testing is whether the UncaughtExceptionHandler is called at the right time. To test whether the handler responds correctly, you can simply call:
_unCaughtExceptionHandler.uncaughtException(thread, ex);
handing it a Thread and a Throwable. This will test whether the handler will behave correctly when it does run.\
These two tests verify whether the code that sets the default handler is correct and whether the handler itself is correct. These are different issues, and it is useful to test both.
It occurs to me that junit may rely on using its own UncaughtExceptionHandler, so when you override that, you break the framework. If that is the case, you might need to build and run the test without using junit.
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.
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).)
In some code I've been reading, I've come across this :
class Someclass
{
public static void main(String[] args) throws IOException
{
//all other code here......
}
}
If main() throws an exception, in this case its an IOException, where is it caught and handled?
EDIT:
Is this considered bad practice? Or is this really common in real world code?
The detailed flowchart of full uncaught exception handling is given here: How uncaught exceptions are handled in Java.
When an uncaught exception occurs, the JVM does the following:
it calls a special private method, dispatchUncaughtException(), on the Thread class in which the exception occurs;
[...which] calls the thread's getUncaughtExceptionHandler() method to find out the appropriate uncaught exception handler to use. Normally, this will actually be the thread's parent ThreadGroup, whose handleException() method by default will print the stack trace.
it then terminates the thread in which the exception occurred.
Therefore you can, if you wish to, create your own custom uncaught exception handler.
It should also be noted that while main is commonly used as a Java application entry point, the method is just like any other methods in that it can also be called from other contexts (e.g. other main methods, or even itself recursively!). In that case, the caller can catch exceptions thrown.
public class SelfCatch {
public static void main(String args[]) throws Exception {
if (args == null) throw new Exception("Hi there!");
try {
main(null);
} catch (Exception e) {
System.out.println("Caught: " + e);
}
System.out.println("Exiting...");
}
}
Output:
Caught: java.lang.Exception: Hi there!
Exiting...
EDIT: Is this considered bad practice?
Or is this really common in real world
code?
It would be in production code, but when rapid prototyping or knocking up test code its often used as its quicker than typing the try {...} catch block. (unless you use a good IDE like Eclipse 3.5 which has an 'Auto wrap in try/catch' feature [auto-detecting any and all exceptions to!] ;-) )
Or your pretty sure it wont be thrown by methods invoked by main().
But even wrapping in a try/catch block will usually result in the same output as if you leave the Exception uncaught, if you simply use e.printStackTrace() ...
At the command line.
EDIT: The entry point is Main. Hence, there is no other method/caller to handle the exception.