I'd like to create a routine that does some logging, takes some other actions, and then throws an Exception. I'd like this routine to be called from many different locations. However, creating Exceptions in this routine means they will have this routine in their stack trace. I would rather the stack trace not report this utility routine. Is there a way to do this without creating the Exception in the caller and passing it to the utility routine?
public static void die(String message) throws MyException {
log(message);
...
throw new MyException();
}
For programmers who are Perl/Java bilingual: how do I carp in Java?
You can set the stack trace of any exception you want to throw:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CarpTest {
public static void main(String[] args) {
new CarpTest().run();
}
public void run() {
methodThatCarps();
}
private void methodThatCarps() {
carp("Message");
}
private void carp(String message) {
RuntimeException e = new RuntimeException(message);
e.fillInStackTrace();
List<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
stack.remove(0);
e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
throw e;
}
}
This will print the following stacktrace at runtime:
Exception in thread "main" java.lang.RuntimeException: Message
at CarpTest.methodThatCarps(CarpTest.java:18)
at CarpTest.run(CarpTest.java:14)
at CarpTest.main(CarpTest.java:10)
Note that as you want the method "carp" does not appear in the stacktrace. However the manipulation of stacktraces shoud only be done with greates care.
If you want to use an Exception to control the flow and what happens afterwards, a good advice it to override the fillInStackTrace() method:
public Throwable fillInStackTrace() {
return this;
}
As a result you'll have an Exception without the stacktrace and with a reduced overhead (filling in the stack trace takes time).
There is no way to removing the throwing function from the stack trace. The whole purpose of the stack trace is to log the exception path so allowing a function to opt out would defeat the purpose.
The only way you could change this is if you returned the exception instead of throwing it. But that forces you to depend on the caller to know to throw the exception.
throw die("someReason).fillInStackTrace();
Modified function
public static Exception die(String message) {
log(message);
...
return new MyException();
}
EDIT
Added the fillInStackTrace() call to ensure the stack is reset to the point of the throw.
http://java.sun.com/j2se/1.3/docs/api/java/lang/Throwable.html#Throwable()
Mmm.. you could subclass exception and override all the methods in it, and wrap the original exception. Internally, generate a new stack trace using the getStackTrace() method from the wrapped exception. I haven't looked at the source of Exception, but you may not even have to override that many methods.
Maybe you should consider approaching the problem from a different direction. Rather than modify the stack trace, why not just have your exception generator method (die in your example) return the exception rather than throw it? Then your call is throw die();.
For example:
// revised die() method:
public static MyException die(String message){
log(message);
//...
return new MyException();
}
// calling code:
throw die("a-whoopsie daisy!");
Now, granted, throw die() might seem a little un-aesthetic, so you could rename die() to newException() or something. But the requirement that the exception processing method does not show in the stack trace is met -- die() (or newException()) returns before the exception is thrown and is therefore not part of the stack to be traced.
Edit: My bad. I've spent so much time working with C# that I forgot that in Java exception stack traces are generated at instantiation, where in C#/.NET exception stack traces are generated at throw-time.
So this trick would work in C#, but not in Java.
Based on what ordnungswidrig said about setting the stack trace, and what unknown (google) said about overriding fillInStackTrace(), I've created a CarpException that does exactly what I want. Note that I found I had to strip out four stack trace frames instead of just one, as I was picking up frames from both Throwable and Exception.
public class CarpException extends Exception {
#Override
public Throwable fillInStackTrace() {
super.fillInStackTrace();
StackTraceElement[] origStackTrace = getStackTrace();
StackTraceElement[] newStackTrace = new StackTraceElement[origStackTrace.length - 4];
System.arraycopy(origStackTrace, 4, newStackTrace, 0, origStackTrace.length - 4);
setStackTrace(newStackTrace);
return this;
}
}
No can do... I tried doing something like this a while back (I was trying to capture the stack trace to log method calls before AOP existed).
The stack trace is filled in when the exception is created, and that's done natively. For the thing I was working on, I ended up reading the stack trace and looking at the second element, but that wouldn't help you here...
You might consider having your method receive a Logger as a parameter to the method. This would allow you to control the logging output based on the calling class.
I would advise against wanting your exception to exclude this part of the stack trace though. When you leave and some new person gets to maintain your code, the are not going to appreciate this non-standard error handling.
Do you throw the stack trace just to be able to analyze it? In that case you could call the getStackTrace() method on the Exception which returns a StackTraceElement[]. There you can filter the elements you don't want (f.ex. the "die" method).
Related
I know there are a number of questions on this topic, but all of them seem to assume one of two things:
You just want to test if an exception was thrown and not caught,
You should test the function that is inside of the try block
directly
I'm not sure how I can apply those options to this case. I have a small try/catch block, like so:
try {
o.getDataContainer().build(...);
o2.setDataContainer(o.getDataContainer());
} catch (final Exception e) {
LOGGER.error("Data set failed", e);
}
As you can see, if o.getDataContainer() returns null, an exception would be triggered. However, that exception is then caught, and the test tool considers it a successful test. Is it possible to test that the exception occurred without changing the code?
I ask because our logging system triggers a trouble ticket if it picks up an exception that is caught and logged. Since it is common human error to forget to guard something like this, I would like to write UTs that can test if an exception was triggered and caught. I can't remove the whole-program protection provided by the catch block, but the error would also cause a degradation of the user experience, since the data isn't being passed along. (I work in a place where minutes of site downtime equal millions of dollars lost.)
In other words: The exception is an error, and we want to log it and investigate it, but in case this manages to trigger on prod, we don't want to risk the whole site going down.
Note: This try/catch sits inside a much larger function with many such try/catch blocks. One could easily argue bad overall design, but fixing it is not an option (without a huge amount of free dev time, at least).
Update: As the task at hand does not allow me to spend a great deal of time on this, I went with a very simple generic test that would fail if the guard and catch were both removed so that I could move on. But, I'm leaving the question unanswered for now in hopes of continuing conversation. I would love to be able to write a simple UT for each new feature that fails if any exceptions are triggered and caught.
Ignoring the issues with this code (Sometimes you've gotta put lipstick on a pig, I guess), this is how I might handle the situation.
I'd use Mockito and mock o2, then use an Answer to ensure the method is invoked.
A test might look like this:
#RunWith(MockitoJUnitRunner.class)
public class TestClass{
#Mock
O2 o2;
#Mock
O1 o1;
boolean exceptionThrown = false;
#Test
public void test(){
Mockito.doAnswer(new Answer<Void>(){
public Void answer(InvocationOnMock invocation) throws Throwable {
exceptionThrown = true;
throw new RuntimeException("some message");
}
}).when(o2).setDataContainer(DataContainer.class);
}
}
Essentially, you can Mock out o2 in your example, and force the exception.
If this doesn't quite do what you want, you may need to mock LOGGER and verify that it's invoked with LOGGER.error("some message");. Unfortunately, mocking statics is not at all elegant, but it can be done with PowerMock.
You could add a custom handler to LOGGER that just throws when an error is logged. For java.util.logging you could do something like:
LOGGER.addHandler(new Handler() {
public void publish(LogRecord record) {
if ("Data set failed".equals(record.getMessage())) {
throw new RuntimeException(record.getThrown());
}
}
public void flush() {}
public void close() throws SecurityException {}
});
I think log4j calls it "Appender," but the same principle should work. See How to create a own Appender in log4j? or How to Create a Custom Appender in log4j2?
This is a simplified class that describes my problem:
public class Main {
enum Test{
First(method()){ // Unhandled exception type Exception
// ...
};
Test(Object obj){
//...
}
}
static Object method() throws Exception{
// ...
if (someCondition){
throw new Exception();
}
}
}
Above someCondition depends on device and some situations and I can not decide in about it now, also as you can see, I do not want to catch Exception in method.
Yes. It is a compilation error.
No. There is no special syntax to deal with this.
I do not want to catch Exception in method.
Unfortunately if you throw a checked exception, it has to be caught further up the call stack. That is a fundamental design principal for the Java language, and one that the compiler enforces strictly.
In this, case there is no way to catch the checked exception. Hence, if you are going to call a method in enum constant parameter (as per your code), the method cannot throw a checked exception1.
Here is a possible workaround, though this is probably a bad idea:
public class Main {
enum Test{
First(methodCatchingException()){
// ...
};
Test(Object obj){
//...
}
}
static Object method() throws Exception{
// ...
if (someCondition){
throw new Exception();
}
}
static Object methodCatchingException() {
try {
return method();
} catch (Exception ex) {
throw new SomeRuntimeException("the sky is falling!", ex);
}
}
}
Another way to look at this problem is to ask yourself what should happen with the exception if the compiler let you write that ... and an exception was thrown? Where would it go?
You can't catch it ... because the enum initialization is like a static initialization.
If the Java runtime completely ignored the thrown exception, that would be really bad.
If the Java runtime crashed, then the model of checked exceptions is broken.
So, what this is saying to me is that the Java language design is right, the Java compiler is right ... and the real problem here is in your application design:
You should not be propagating a checked exception here. If an exception occurs in this context it is categorically NOT a recoverable error.
Maybe it is inadvisable to use an enum for this ... because of the potential for non-recoverable initialization errors.
(Note that if this method call terminates due to an unchecked exception, it will turn it into an ExceptionInInitializerError. In addition, the JVM will mark the enum class as uninitializable, and will throw an NoClassDefFoundError if your application attempts to use it; e.g. via Class.forName(...).)
I assume that Exception is used here for illustration purposes. It is a bad thing to declare methods as throws Exception or to throw new Exception(...)
1 - I had a look at the JLS for something to back this up. As far as I can tell, the spec does not mention this situation. I'd have expected to see it listed in JLS 11.2.3. However, it is clear that a compiler cannot allow a checked exception to propagate at that point as it would "break" the model of how checked exceptions work.
I don't think you want to be throwing a checked exception here (which is what Exception is). The reason: you're invoking the call of method inside of the constructor of Test. There's really not a clean way to deal with it.
While the obvious choice here is to switch to RuntimeException, I want you to reconsider throwing the exception in the first place. Since your enum will only ever have First declared in it, does it really make sense for it to throw an exception when it's being instantiated? Personally, I don't think it does; whatever dangerous operation it's doing should be deferred until you want to invoke it, and then would you want to throw your exception.
I've been attempting to write Java exception handlers for a while now, have tried multiple methods and have even visited/read through Oracle's "The Java Tutorials" and I still cannot get it straight. I'm unsure what I am doing wrong. I have a given class (TooLowException) for the exception that I am trying to use. In the method I am attempting to use it in I am using an argument that I need to catch if it is less than zero.
public int func(int num) throws TooLowException {
int blah = num + 1;
if ( blah < 0) {
return blah;
}
else {
String error = "Input is too low.";
throw new TooLowException(error);
}
}
This is the exception class:
public class TooLowException extends Exception {
public TooLowException(String response) {
super(response);
}
}
I'm getting the error in Oracle "Unhandled Exception type TooLowException". I've also attempted the try-catch method as well, but it also doesn't work for me. Hopefully this is enough information for someone to point out what I'm doing incorrectly. I need to be set right in my ways of exception handling.
Taken from what info you've given, it seems that you need to have a try/catch block somewhere in your code. Basically somewhere in your application that func(int) method is being called, or needs to be called if you're running into a compiler error telling you the "Unhandled Exception type TooLowException." General rule for exceptions is Handle/Catch or Declare. This can be broken down like this:
Handle/Catch: If you choose to handle the exception, then the "throws" declaration should be removed from the method signature ("public int func(int num) throws TooLowException" becomes "public int func(int num)"). The idea behind this approach is that you as the programmer intend to handle this type of exception because it's specific enough to the method that you don't want external code to have to worry about handling the exception outside of the scope of the method. This requires that you "handle" the exception yourself, by using a try/catch block.
Declare: This is the method you went with. You are stating that whatever class uses this function has the burden of handling the exception with the try/catch block. This would be used if the method you wrote is generic enough that many different applications can use it and that handling the exception should be application specific, i.e., it's up to other developers to handle it in their own way. Some people like to just log things, others like to have a different control flow execute upon receiving certain exceptions.
Here's what works, sorry if it basically answers an exercise you needed to do, but it's in the interest of helping you! Please take time to understand what is happening here:
public class YourClassThisStuffIsIn {
public static int func(int num) throws TooLowException {
int blah = num + 1;
if ( blah < 0) {
return blah;
}
else {
String error = "Input is too low.";
throw new Exception(error);
}
}
public static void main(String[] commandlineArgument){
try {
YourClassThisStuffIsIn.func(3);
} catch (TooLowException tle){
System.out.println("Caught " + e);
}
}
}
When you click run in your IDE, or you run through the console, the JVM looks for the main method with the correct signature. In this case it finds it, and it executes the main method. First line is a try, meaning the JVM has to prepare itself for the possibility of a problem in the application, allowing it to recover in case an exception is thrown. In this case, the only exception that can be thrown is a TooLowException, which you have written how to handle it inside the catch block. Your way of handling it is simply printing the stack trace out, which is fine I think in this situation.
I've changed your example slightly, making your method static just so it's quicker to write. I also suspect that the intent is that the commandLineArgument is meant to be the number passed into the func(int) method, so in that case you're looking at the func method to look like func(Integer.parseInt(commandlineArgument[0])).
Bonus points for you is noticing that parseInt throws a NumberFormatException too, but you will of course remember that java.lang.RuntimeException and its subclasses aren't checked exceptions so there is no requirement to catch them, though it is good practice!
If I run the following test, it fails:
public class CrazyExceptions {
private Exception exception;
#Before
public void setUp(){
exception = new Exception();
}
#Test
public void stackTraceMentionsTheLocationWhereTheExceptionWasThrown(){
String thisMethod = new Exception().getStackTrace()[0].getMethodName();
try {
throw exception;
}
catch(Exception e) {
assertEquals(thisMethod, e.getStackTrace()[0].getMethodName());
}
}
}
With the following error:
Expected :stackTraceMentionsTheLocationWhereTheExceptionWasThrown
Actual :setUp
The stack trace is just flat out lying.
Why isn't the stack trace rewritten when the exception is thrown? I am not a Java dev, and maybe I'm missing something here.
The stack trace is created when the exception is instantiated, not when it is thrown. This is specified behaviour of the Java Language Specification
20.22.1 public Throwable()
This constructor initializes a newly created Throwable object with null as
its error message string. Also, the method fillInStackTrace (ยง20.22.5) is
called for this object.
....
20.22.5 public Throwable fillInStackTrace()
This method records within this Throwable object information about the
current state of the stack frames for the current thread.
I don't know why they did it that way, but if the specification defines it like that, it is at least consistent on all the various Java VMs.
However, you can refresh it by calling exception.fillInStackTrace() manually.
Also note that you should use Thread.currentThread().getStackTrace() instead of using new Exception().getStackTrace() (bad style).
The stacktrace of the exception is filled in at creation time of the exception. Otherwise it would be impossible to catch an exception, handle it and rethrow it. The original stacktrace would get lost.
If you want to force this you have to call exception.fillInStackTrace() explicitly.
Because you didn't ask that that stack trace be rewritten. It was set when you created it in the setUp method, and you never did anything to alter it.
The Exception class doesn't give you any opportunity to set the method name; it's immutable. So there's no way that I know of where you could re-set the method name, unless you wanted to resort to something heinous like reflection.
Your #Test annotation doesn't tell me if you're using JUnit or TestNG, because I can't see the static import, but in either case you can run a test to see if a particular exception is thrown by using the "expected" member in the #Test annotation.
You wouldn't want throwing an exception to alter the stack track or you couldn't re-throw an exception safely.
public void throwsException() {
throw new RuntimeException();
}
public void logsException() {
try {
throwsException();
} catch (RuntimeException e) {
e.printStrackTrace();
throw e; // doesn't alter the exception.
}
}
#Test
public void youCanSeeTheCauseOfAnException(){
try {
logsException();
} catch(Exception e) {
e.printStrackTrace(); // shows you the case of the exception, not where it was last re-thrown.
}
}
The stack trace in the exception corresponds to the "new" operation, nothing else.
I think the assumption is that you won't be instantiating an exception unless you are in the process of throwing it, so why pay the price to get the stack trace twice?
It would be difficult to recreate the stack trace while throwing it, as that is just sending the object out.
The exception should be fully setup before the throw, so part of the instantiation is to get the stack trace.
UPDATE:
You can call fillInStackTrace() to resolve this.
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.