i recently started using sonar as code review tool.
When i analysed my code running sonar,
it reflected printing stack trace as violation of java coding standard.
As an alternative to stack trace, I tried:
e.getcause()
but this did not clear the exception as done by stack trace
Error handling can be tricky in any environment, java included. I haven't used sonar, but I can comment on general good practices for java error handling.
e.printStackTrace() is generally discouraged because it just prints out the stack trace to standard error. Because of this you can't really control where this output goes.
The better thing to do is to use a logging framework (logback, slf4j, java.util.logging, log4j, etc) because then you can control where the errors are logged to and what the log retention policy is.
And generally you'll want to catch the exception and if it's unexpected behavior, log it and either throw a new exception (probably specific to your application) or do whatever you have to do to continue operating gracefully.
If you're using java.util.logging, you can do something like the following:
class YourClass
{
Logger logger = Logger.getLogger(YourClass.class.getName());
...
public void someMethod() throws YourException
{
try
{
// your code here
} catch (NullPointerException e)
{
String message = "Unexpected NullPointerException in processing!";
logger.log(Level.ERROR, message, e);
throw new YourException(message, e);
}
}
}
Hope this helps!
A few thoughts:
I presume from the title you were using e.printStackTrace(). This does not "clear the exception", so I'm not sure exactly what your issue really is on that point. In java "clear the exception" doesn't make any sense at all in this context.
e.printStackTrace() is "not a good idea" because it writes to standard out. Much better to write such detail to a log file for later diagnostics, rather than put it out in front of a user (though that could depend on how the program actually runs). Your run-time environment may have something to say about use of standard output.
e.getCause() will return, if available, an "underlying exception" that may have been a "root cause" for the exception e. Must stack traces will show this after an initial stack dump denoted by "Caused by: : ..."
If you choose to try to capture and display/log an exception yourself - you might use e.printStackTrace(PrintStream s) or e.printStackTrace(PrintWriter s).
You'd be best served using a logging tool, as suggested by Matt.
Related
Since I updated to Java 11, I am getting an exception which is proving impossible to pin down.
Please note: The classes the exception mentions are nowhere to be found in my own code.
The stacktrace only shows which bit of my code meets the problem, but gives no context at all for the actual code (third party) that causes the problem.
This exception has been asked about before in Stackoverflow, but I can only solve the problem if I can find which third party code is causing this and upgrade it, which will (hopefully) mean that I can see the back of it.
The exception is as follows:
java.lang.ClassCastException: class sun.net.www.protocol.https.HttpsURLConnectionImpl cannot be cast to class com.sun.net.ssl.HttpsURLConnection (sun.net.www.protocol.https.HttpsURLConnectionImpl and com.sun.net.ssl.HttpsURLConnection are in module java.base of loader 'bootstrap')
I strongly suspected some very old apache HttpClient classes, and have replaced them with the java.net.http classes (available since Java 11), but to no avail.
The question is: is there a way to find which .jar contains code that uses HttpsURLConnectionImpl and HttpsURLConnection?
And does anybody know what the rather unhelpful indication that they are in module java.base of loader 'bootstrap' means?
are in module java.base of loader 'bootstrap'
It means that class sun.net.www.protocol.https.HttpsURLConnectionImpl is loaded by the bootstrap loader and are loaded as part of the module base. This is completely useless information: That module is the core java stuff (java.lang.String is in there too), and that loader is the one that loads that stuff. No wonder; sun.* classes are implementation details that are part of what all JDKs ship with out of the box. It provides nothing useful whatsoever for fixing the problem.
The exception is as follows:
There are only two options.
You forgot to paste the stack trace that follows the stuff you did paste. That stack trace is the important part, and lets you know exactly where to look.
You have broken exception handling.
I'm guessing it's option 2 - it's a common thing and perpetuated by manual tutorials. The fix is unfortunate: Go through all your code and fix the bad code. A search for .getMessage() should get you pretty far. It sure sounds like you are doing something like this:
try {
.. code here ..
} catch (Exception e) {
log.warn(e.getClass() + ": " + e.getMessage());
}
or similar. This is always bad - do not just 'log/print' and forget about an exception: You want any exception to be handled, OR thrown onwards. You never want to take an exception whose meaning is not clear as you write the code, and just 'swallow' it. Update your IDE's template settings for generating try/catch clauses; the proper way to write code that just sort of goes; "Exceptions? Um... I do not want to think about those right now / I dont know what they mean / I do know but there's nothing useful I can do about them at this point or I can't fathom how they could occur", which covers most of the time you need to deal with an exception, is like this:
try {
.. stuff ..
} catch (SomethingIDoNotWantToHandleException e) {
throw new RuntimeException("unhandled", e);
}
This will ensure that the place you see that error now has the actual stack trace which will then let you know which library you need to update.
The error was coming from pd4ml, a java library for producing pdfs.
I updated to the latest version (3.11.5), which solved the problem.
2 Questions:
What is the difference between e.printStackTrace(System.out) and e.printStackTrace() ?
Is it safe (from the production point of view) to replace e.printStackTrace(System.out) and e.printStackTrace() with log4j using logger.error("", e) if i want to print out the stack trace in my log file?
e.printStackTrace() is same as e.printStackTrace(System.err). So, it prints to standard error. e.printStackTrace(System.out)` prints to system out.
You should never do e.printStackTrace(), System.out.print(), System.err.print() on a production code. You should always use logger methods, and configure your logger.
I had a strange problem today... I'm going to make a simplified example since it "worth a thousands words" :D
public class Application() {
public static void main(String[] args) {
try {
A a = new A(); // this may throw exceptions
// (which will cause an ExceptionInInitializerError)
} catch (Throwable t) {
JOptionPane.showMessageDialog(null, "Oooops!");
System.exit(1);
}
}
}
Since it's a stand-alone application with a Swing GUI, my goal is to give a message to the user in case of any problems (in this case at startup)... the code above works in Eclipse IDE but when I export the project as executable jar by double-clicking on it, well, it just won't open.
So I try to execute it in cmd with java -jar application.jar and it prints in the shell that there was an ExceptionInInitializerError.
Why the error was not caught?
It doesn't work even if I specify catch (ExceptionInInitializerError e).
EDIT:
After more indepth debugging, I found out that this problem only happens when two particular exceptions occur and the latter occurs in the catch block of the former.
I corrected the bug by changing the order of some checks that I do on startup.
The problem btw should never happen since it was originated by a volountary mistake of the JDBC driver class name to load in a static block.
Well, at least it made me clearly understand why constructors and static initialization blocks should not throw exceptions: it makes debugging almost impossible in the case in which the class that throws the exception is used by many classes, since it may become very hard to find out when the class is loaded.
I can think of three possible explanations for an ExceptionInInitializerError not being caught in your example:
It could be being thrown by JOptionPane.showMessageDialog(null, "Oooops!");
It could be thrown before main is called.
It could be thrown on a different stack.
In fact, I think that the 2nd one is the most likely, as ExceptionInInitializerError is thrown when some unchecked exception is thrown (and not caught) during the initialization of a class. That could well be happening before you enter the try block.
I have a method that sometimes throws an exception:
this.items[index] = element;
And I have a unit test that asserts that the exception that ought to be thrown is actually thrown:
try
{
doSomethingWithIndex(-1);
Assert.fail("should cause exception");
}
catch (IndexOutOfBoundsException expected)
{
Assert.assertNotNull(expected.getMessage());
}
This test runs as part of the continuous build and sometimes, occasionally it fails because getMessage() in fact returns null. Why would this happen? My code can never throw an exception with a null message.
EDIT
My original code example was misleading, the thrown exception is actually coming from directly indexing an array. I can reproduce the same behavior with a custom thrown exception though.
I added the suggested code:
catch (IndexOutOfBoundsException expected)
{
if (expected.getMessage() == null)
{
expected.printStackTrace();
}
Assert.assertNotNull(expected.getMessage());
}
The console output is missing the stack trace in addition to the cause. Here's the full output:
java.lang.ArrayIndexOutOfBoundsException
Found the answer on a similar question.
The JIT compiler will optimize away stack traces in certain exceptions if they happen enough.
The JVM flag -XX:-OmitStackTraceInFastThrow prevents this behavior and seems to fix the flickering unit tests.
Try printing stack trace of exception when it has null message. It's possible that some other code throws it. Like you actually accessing past array length.
You wrote that:
"My code can never throw an exception with a null message"
Are you yousing any 3rd party library? I assume standard java codes never throw exceptions like this above, but some pourly coded jar... :)
In my code base is the (very simplified) following:
public static void main (String[] args) {
System.out.println("Starting application");
try {
System.out.println("About to validate");
validate(args);
catch (Exception e) {
e.printStackTrace();
}
}
public static void validate(String[] args) {
System.out.println("Your first arg is " + args[0]);
if (someProblemWith(args)) {
System.out.println("Your args are wrong. It should be: ...");
throw new BadArgsException(e);
}
}
Which works fine. Note that my example code above is contrived and simply meant to show multiple log statements prior to exception and stack trace printing. This often means that my last logging statement is lost in the middle of the stack trace output. Is there an elegant way to ask the e.printStackTrace() statement to wait until the System.out has finished its work? I'm essentially looking for the stacktrace to be the very last thing printed when an error occurs. Here's a sample output of my program above:
java.lang.Throwable
....
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
Your args are wrong. It should be: ...
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
The reason you are seeing the stack trace being printed between the System.out.println() statements, is because System.out is buffered, while System.err (used by stack trace) is unbuffered.
If you want the text to be displayed in the exact order in which things are happening, you need to "unbuffer" the System.out. The simplest way is to also just use System.err there instead of System.out.
Otherwise, call System.out.flush() before your stack traces happen in the catch clauses.
Option 2: Use the Logger class.
Option 3: Implement your own "buffer". In other words, first write everything to your own buffer, including the stack traces (using .toString() or however you wish) and then in the catch flushing you own buffer. (This is kind of redundant since you can just flush the System.out anyway).
-==-
FROM COMMENT
Sure. The Logger class can be used to create a much more robust and detailed logging experience. This is typically what is done in applications. An instance of the Logger class is grabbed from the Logger class (it is a singleton), taking as parameter the class from which is will be used. Then you log messages to it by using the .log() method. The nice thing about the Logger class is that you can set levels on it (example DEBUG, WARN...) and you are then able to filter / display only what you want. The "log" messages are then displayed in a uniform way in the console, typically in the format of:
2010-11-23 14:45:32,032 DEBUG [MyClass] Your message
The above format is from log4j, but you can use the standard Java Logger. The output should be similar, maybe a bit less. But I'm sure it can be configured.
Call e.printStackTrace(System.out);. Or, if you need it for debugging only, you can separate the process' output and error from the command line: .... 1>output.log 2>error.log