Get Nashorn script line number during interpretation - java

My code uses Nashorn to provide scripting functionality to the user, with many classes and functions implemented on Java exposed to the scripts through Nashorn.
One of the tasks of the program is of course to report any errors relating to the scripts to the user when encountered. This is very simple if a ScriptException occurs, as simply catching the exception and using the method getLineNumber() returns the correct value. However, occasionally an exception occurs not due to the syntax, but due to the way the Java-side code is called, for example due to a null parameter which was supposed to be a valid object. These cause other kinds of exceptions, which can still be caught around the call to the eval method, but since these do not have a getLineNumber() method its impossible to guess where the interpreter was left.
Is there a way I can get the last executed line somehow from the Nashorn engine?
The code roughly looks like this:
try {
engine.eval( script);
// successful
return -1;
} catch ( ScriptException e)
{
// the ScriptException reports the line number
return e.getLineNumber();
}
catch ( Exception e)
{
// is it possible to get the line number here too?
// ...
return lineNumber;
}

There is a standard Nashorn API to get StackTraceElement[] for "script frames" from a given arbitrary Throwable object.
jdk.nashorn.api.scripting.NashornException class has
public static StackTraceElement[] getScriptFrames(Throwable exception)
method
https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/NashornException.html#getScriptFrames-java.lang.Throwable-
You can pass arbitrary Throwable object and get back StackTraceElement array for the script frames. The top most script frame would be the zero'th element of the array and you can call getLineNumber on the StackTraceElement object.
This way, you can avoid dependency on nashorn internal package prefixes.

You could walk the stack of the exception, find the first StackTraceElement where the class name starts with jdk.nashorn.internal.scripts. and report its line number:
for(StackTraceElement ste: e.getStackTrace()) {
if (ste.getClassName().startsWith("jdk.nashorn.internal.scripts.")) {
return ste.getLineNumber();
}
}
return -1; // couldn't figure it out
You can also try to use ste.getFileName().endsWith(".js") if that's more robust for your situation.

Related

Exception Handling in JS using Graal

I work on a Java application that makes fairly heavy use of Javascript to form the business logic/glue. It runs using Graal. This all works fine, but we struggle with effective error handling.
This is essentially how the JS is executed:
try {
Context context = Context.newBuilder("js").allowAllAccess(true).build()
Source s = Source.newBuilder("js", src, "script").build();
context.eval(s);
} catch (Exception e) {
LOGGER.error("Exception occurred in JavaScript:...", e);
}
So when errors happen we log them somewhere so we can do some postmortem, etc. It's possible to get the JS stack trace in these logs out of the PolyglotException that Graal throws, which is great. However, things are more complicated when some JS code has called back into Java-land, and a Java exception has been thrown:
var x = callJavaFunction("invalid parameter"); // Throws a NoSuchElementException, for example
The PolyglotException has an asHostException() method that returns the original Java-land exception, and my code that executes the JS files is smart enough to understand this and produce a useful error log. The problem arises when the JS code has tried to catch this itself, for whatever reason:
try {
var x = callJavaFunction("invalid parameter"); // NoSuchElementException
} catch (e) {
doSomeCleanup();
throw e;
}
Now we have lost the original Exception, and even worse, the JS-stack trace now just shows us the catch block, instead of where the cause was. isHostException() returns false, because this is just a JS error now. I cannot find a way to get at the original cause, which makes diagnosing errors quite difficult, especially when they have come out of a production system. The original Java exception message ends up in the JS-error object, which is helpful, but we don't have the stack trace, which is not.
What approaches can I take to try and address this?
One thought I had: Can I hook into the GraalVM and get a callback whenever a host-exception is thrown? At least that way I could have a log saying "the following Java Exceptions were thrown during execution" which I could attach to the error report. So far I've not been able to find a way to achieve this.

How to suppress Cucumber/Junit assertion stack trace

I have a cucumber scenario and the step uses assertEquals. My results report shows the stack trace which is not end user friendly. How can I suppress it
Scenario: Add two numbers
Given I have two inputs "3" and "2"
When I add them
Then the output should be "15"
You're correct in observing that the default XML output (assuming you're not outputting to JSON or text, but you didn't say) from a Junit tests show stack traces for failed steps. This isn't actually a Cucumber thing. CucumberOptions won't help you here.
You can:
Use a different or custom Runner for your test and then setup a tag that controls what is included in the output, or what will be read by the CI software of your choosing. For example the Confulence API API for doing this tells how "debugger"
Same type of deal for Ant Scripts to tweak the output, so that is doesn't show the output. A good Tutorial for learning how to use Any scripts to fire off your Cucumber JUnit Test is here.
Other have build a custom formatter for JUnit by implementing XMLJUnitResultFormatter API, explained more here - How do I configure JUnit Ant task to only produce output on failures?
Hope that gives you what you need.
I was also facing same issue with my Cucumber-Selenium-Java project. In the cucumber reports, it was generating around 40 lines of stacktrace. Due to this, it was impacting look and feel of the report. And the end user/client was little concerned about it. Because he/she was not really able to figure out the actual use of this stacktrace. So, I came up with below idea/approach. It's little bit tricky but, it's worthy.
Few notes before starting:
We cannot completely disable stacktrace in in all the cases. But we can modify the stacktrace and then, re-throw the new exception with useful and shortened stacktrace.
You need to be aware about frequently faced exceptions, errors. So that, we can create custom exception depending on the exceptions.
In the stacktrace it will generate few line of code from wrapper APIs, few lines from Junit/TestNg, few lines for java and selenium and there will be only one or two lines in the stacktrace, where actually our issue occurred.
Our test classes must be in unique package. So that, we can filter the stacktrace trace with package name and get the class name, line number and method name of actual issue and we can use this information in throwing custom exception. Hence, it will be easy to figure out the actual line of issue occurred. In my case all the classes were in package named "page". If you have more than one packages for your classes, then you can accordingly add string conditions in below code.
We need to wrap the test code in try-catch block. And while catching, we need to use Throwable class not exception class. Because, if there is any assertion failure, then Exception class won't be able to handle the issue as you know all the assertions come under Error class and Throwable is the parent of Error and Exception.
If we throw the new exception in catch block, then, it will change the line number in stacktrace, where actual issue occurred. So it will be difficult to figure out the actual line of issue. In order to avoid it, we need to get the class name, line number, method name of actual issue and store it in StackTraceElement class and use it in throwing new exception.
Some exceptions like "NoSuchElementException" provides lot of information in their cause and most of it is not really required, So we need to modify the content of it's message by using substring(), indexOf() and replaceAll() methods of String class in Java. And then, provide the modified information in new exception.
Few important Java method from Throwable java class and their description: (i) getStackTrace(): This method will return us array of StackTraceElement class. StackTraceElement class will provide us the class name, method name, line number at which issue is occurred. (ii) setStackTrace(): This method is used to provide a custom stacktrace to new Exception. (iii) getCause(): This method will provide the issue message from cause of exception. But sometimes, it might return null. Because for some exceptions "cause" might not be specified. So this needs be surround in try catch block and here we need to use getMessage() method for getting the actual error message. (iv) getClass(): This method will return the actual exception class name. We will use this method for figuring out the exception class name and then, we will use it for providing specific implementation for different different exception classes. Note: "getClass()" method is not from "Throwable" class. It is from Object class.
You need to create a common method for handling all the exceptions and reuse this method in all the required classes. e.g.: I have named the method as "processException" and placed it in "ReusableMethod" class.
Note that, I am using package name "page" in below method (line#8), because all my test classes are placed in this package. In your case you need to update the package name as per your need. Also, I have written custom cases for two exceptions only: NoSuchElementException & AssertionError. You might need to write more cases as per your need.
public void processException(Throwable e) throws Exception {
StackTraceElement[] arr = e.getStackTrace();
String className = "";
String methodName = "";
int lineNumber = 0;
for (int i = 0; i < arr.length; i++) {
String localClassName = arr[i].getClassName();
if (localClassName.startsWith("page")) {
className = localClassName;
methodName = arr[i].getMethodName();
lineNumber = arr[i].getLineNumber();
break;
}
}
String cause = "";
try {
cause = e.getCause().toString();
} catch (NullPointerException e1) {
cause = e.getMessage();
}
StackTraceElement st = new StackTraceElement(className, methodName, "Line", lineNumber);
StackTraceElement[] sArr = { st };
if (e.getClass().getName().contains("NoSuchElementException")) {
String processedCause = cause.substring(cause.indexOf("Unable to locate"), cause.indexOf("(Session info: "))
.replaceAll("\\n", "");
Exception ex = new Exception("org.openqa.selenium.NoSuchElementException: " + processedCause);
ex.setStackTrace(sArr);
throw ex;
} else if (e.getClass().getName().contains("AssertionError")) {
AssertionError ae = new AssertionError(cause);
ae.setStackTrace(sArr);
throw ae;
} else {
Exception ex = new Exception(e.getClass() + ": " + cause);
ex.setStackTrace(sArr);
throw ex;
}
}
Below is the sample Method to showcase the usages of above method in Test Class methods. We are calling the above created method by using the class reference, which is "reuseMethod" in my case. And we are passing the caught Throwable reference "e" to the above method in catch block:
public void user_Navigates_To_Home_Page() throws Exception {
try {
//Certain lines of code as per your tests
//element.click();
} catch (Throwable e) {
reuseMethod.processException(e);
}
}
Here are few screenshots for implementation of NoSuchElementException:
Before Implementing this approach:
After Implementing this approach:

Can I throw exception based on method signature in ASM?

I am fiddling with ASM framework for sometimes. I just want to catch exceptions.
So far , I am able to insert try-catch blocks in bytecode and catch the exception.
This is what I am doing now.
public void visitMaxs(int maxStack, int maxLocals)
{
// visit try block end label
this.visitLabel(lblTryBlockEnd);
// visit normal execution exit block
//this.visitJumpInsn(Opcodes.GOTO, exitBlock);
// visit catch exception block
this.visitLabel(lblCatchExceptionBlockStart);
// store the exception
this.visitVarInsn(Opcodes.ASTORE, 1);
super.visitTypeInsn(Opcodes.NEW, "java/lang/Exception");
super.visitInsn(Opcodes.DUP);
// load the exception
this.visitVarInsn(Opcodes.ALOAD, 1);
// Initializing the exception object with the throwable cause
super.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Exception", "<init>", "(Ljava/lang/Throwable;)V");
// calling jensor method to write
super.visitMethodInsn(Opcodes.INVOKESTATIC,
"test/ExceptionHandleTest",
"exceptionHandler",
"(Ljava/lang/Exception;)V");
// call printStackTrace()
this.visitInsn(Opcodes.ATHROW);
// exit from this dynamic block
this.visitLabel(exitBlock);
super.visitMaxs(maxStack+2, maxLocals);
}
`
Now , I do not want to throw every caught exception ( as I am doing athrow every time now ) , instead I want to throw only if it matches with exception parameter of method signature of MethodVisitor.
I tried to do so , but got Falling off the end of the code class verify error.
Is it possible to do using ASM ?
Thanks in advance.
You can do this, I suggest your write what you want in Java and ASMifier the byte code to see how it is structured.
There is an ASM plugin for IDEs which make this easier.
Your code fragment gives too little information about what you really do. You say that you want to (re)throw the exception under a certain condition only but you don’t say what you want to do otherwise. That perfectly matches the verifier error: if you skip the throw instruction under certain conditions and have not provided an alternative end of the method your code falls off the end of the method. You have to provide code for that case, e.g. a controlled return. The alternative is not to catch exceptions that don’t meet your criteria but that would end up the same behavior as re-throwing all exceptions.

Java 7: throw exception without stack trace

EDIT2
#paradigmatic made a good point in suggesting to redirect rather than throw the exception; that solves the logging issue. The problem in Play 2 is that redirects need to occur within so-called Action scope, which is not always the case with date parser calls.
As a workaround, I went with Play's global interceptor, presumably the equivalent of a Java servlet filter.
val ymdMatcher = "\\d{8}".r // matcher for yyyyMMdd URI param
val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd")
def ymd2Date(ymd: String) = ymdFormat.parseDateTime(ymd)
override def onRouteRequest(r: RequestHeader): Option[Handler] = {
import play.api.i18n.Messages
ymdMatcher.findFirstIn(r.uri) map{ ymd=>
try { ymd2Date( ymd); super.onRouteRequest(r) }
catch { case e:Exception => // kick to "bad" action handler on invalid date
Some(controllers.Application.bad(Messages("bad.date.format")))
}
} getOrElse(super.onRouteRequest(r))
}
EDIT
Here 's a little context to work with:
// String "pimp": transforms ymdString.to_date call into JodaTime instance
class String2Date(ymd: String) {
def to_date = {
import play.api.i18n.Messages
try{ ymdFormat.parseDateTime(ymd) }
catch { case e:Exception => throw new NoTrace(Messages("bad.date.format")) }
}
val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd")
}
#inline implicit final def string2Date(ymd: String) = new String2Date(ymd)
and a test custom exception handler:
public class NoTrace extends Exception {
static final long serialVersionUID = -3387516993124229948L;
#Override
public Throwable fillInStackTrace() {
return null;
}
public NoTrace(String message) {
super(message);
}
}
Calling the date parser on an invalid yyyyMMdd string logs 30 line stack trace to the log (this occurs upstream by Play framework/Netty container, better than default 100 line trace):
"20120099".to_date
ORIGINAL
Have an issue where my application.log is getting filled with errors related to a uri date parser operation that should succeed given a valid yyyyMMdd uri date.
However, some users try to circumvent this by entering invalid dates in hopes of gaining free access to paid subscriber-only content. It's pointless, as it simply won't work, but regardless, I have MBs of these error traces in my application log.
Is there a way to throw a truly trimmed down Exception to the log? I found this SO answer, but in my application it looks like the container (Play framework on Netty) gets into the mix and logs its own 30 line stack trace to the log (30 lines is better than 100, but still 29 too many)
Similarly, I found this thread in regard to Java 7 and the new option to suppress stack trace; however, for some reason, despite being on Java 1.7, with Eclipse configured for Java 1.7, only the old 2 param method of Throwable is available (and I do see the 4 param method when I click through to the Throwable class; maybe a Scala 2.9.2 library issue?)
At any rate, ideally I can simply log a 1-line exception message and not the kitchen sink.
Simply override this method in your custom exception class:
#Override
public Throwable fillInStackTrace() {
return this;
}
after adding this method your trace method will not print
Your trouble is that although you can suppress the stacktrace of the exception your own code threw, there is nothing you can do about the exception it will be wrapped into by the framework. The only avenue I can see is not allowing the framework to catch your exception at all (doing your own top-level handling) or tweaking the logging configuration.
I think you have two options:
Control the logging to not save stack traces for some exceptions.
Write a post-processor that filters out the traces from the log file.
Unless you are in danger of running out of disk space, I think #2 is the better option, because if you do have a bug you can go back to the full log and have all the exception history.
The philosophy behind idea #2 is that disk space is cheap, but information can be precious during debug. Log a lot of data. Normally, use scripts to examine the log after it has been written to disk.
For example, if there is a type of log entry that you never expect to see, but that demands immediate action if it does appear, write a script that searches for it, and send you an e-mail if it finds one.
One of the most useful forms of script in this approach is one that drops stack trace lines. Usually, you only need to know what exceptions are happening, and the stack trace takes up a lot of screen space without telling you much. If you do need to investigate an exception, go back to the full log, find the exception line, and look at the stack trace and at what was happening immediately before the exception.
If there are too many of your date exceptions, have the script drop even the exception line. If you want to track how often they are happening, run a script that counts date exceptions per hour.
That sort of script typically costs a few minutes of programming in your favorite regex-capable script language.

When should I use an exception in java

I was trying to understand why to use exceptions.
Suppose if I have an program,
(without using try/catch)
public class ExceptionExample {
private static String str;
public static void main(String[] args) {
System.out.println(str.length());
}
I got exception
Exception in thread "main" java.lang.NullPointerException
at com.Hello.ExceptionExample.ExceptionExample.main(ExceptionExample.java:22)
Now using try/catch,
public class ExceptionExample {
private static String str;
public static void main(String[] args) {
try {
System.out.println(str.length());
} catch(NullPointerException npe) {
npe.printStackTrace();
}
}
}
I got Exception,
java.lang.NullPointerException
at com.Hello.ExceptionExample.ExceptionExample.main(ExceptionExample.java:9)
Now my question is,
In both the cases I have got the same message printed. So what is the use of using try/catch? and
What can we do after catching exception, in this case I have printed the stack trace. Is catch used only for printing the trace or for finding exception details using getMessage() or getClass()?
The difference is pretty big, actually.
Take the first one and add a line after the print:
public class ExceptionExample {
private static String str;
public static void main(String[] args) {
System.out.println(str.length());
System.out.println("Does this execute?");
}
}
You'll see that Does this execute? isn't printed because the exception interrupts the flow of the code and stops it when it isn't caught.
On the other hand:
public class ExceptionExample {
private static String str;
public static void main(String[] args) {
try {
System.out.println(str.length());
} catch(NullPointerException npe) {
npe.printStackTrace();
}
System.out.println("Does this execute?");
}
}
Will print both the stack trace and Does this execute?. That's because catching the exception is like saying, "We'll handle this here and continue executing."
One other remark, the catch block is where error recovery should happen, so if an error occurs but we can recover from it, we put the recovery code there.
Edit:
Here's an example of some error recovery. Let's say we have a non-existent file at C:\nonexistentfile.txt. We want to try and open it, and if we can't find it, show the user a message saying it's missing. This could be done by catching the FileNotFoundException produced here:
// Here, we declare "throws IOException" to say someone else needs to handle it
// In this particular case, IOException will only be thrown if an error occurs while reading the file
public static void printFileToConsole() throws IOException {
File nonExistent = new File("C:/nonexistentfile.txt");
Scanner scanner = null;
try {
Scanner scanner = new Scanner(nonExistent);
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException ex) {
// The file wasn't found, show the user a message
// Note use of "err" instead of "out", this is the error output
System.err.println("File not found: " + nonExistent);
// Here, we could recover by creating the file, for example
} finally {
if (scanner != null) {
scanner.close();
}
}
}
So there's a few things to note here:
We catch the FileNotFoundException and use a custom error message instead of printing the stack trace. Our error message is cleaner and more user-friendly than printing a stack trace. In GUI applications, the console may not even be visible to the user, so this may be code to show an error dialog to the user instead. Just because the file didn't exist doesn't mean we have to stop executing our code.
We declare throws IOException in the method signature instead of catching it alongside the FileNotFoundException. In this particular case, the IOException will be thrown here if we fail to read the file even though it exists. For this method, we're saying that handling errors we encounter while reading the file isn't our responsibility. This is an example of how you can declare an irrecoverable error (by irrecoverable, I mean irrecoverable here, it may be recoverable somewhere further up, such as in the method that called printFileToConsole).
I accidentally introduced the finally block here, so I'll explain what it does. It guarantees that if the Scanner was opened and an error occurs while we're reading the file, the Scanner will be closed. This is important for many reasons, most notably that if you don't close it, Java will still have the lock on the file, and so you can't open the file again without exiting the application.
There are two cases when you should throw an exception:
When you detect an error caused by incorrect use of your class (i.e. a programming error) throw an instance of unchecked exception, i.e. a subclass of RuntimeException
When you detect an error that is caused by something other than a programming error (invalid data, missing network connectivity, and so on) throw an instance of Exception that does not subclass RuntimeException
You should catch exceptions of the second kind, and not of the first kind. Moreover, you should catch exceptions if your program has a course of action to correct the exceptional situation; for example, if you detect a loss of connectivity, your program could offer the user to re-connect to the network and retry the operation. In situations when your code cannot adequately deal with the exception, let it propagate to a layer that could deal with it.
try/catch will prevent your application from crashing or to be precise- the execution will not stop if an unintentional condition is met. You can wrap your "risky" code in try block and in catch block you can handle that exception. By handling, it means that do something about that condition and move on with execution.
Without try/catch the execution stopped at the error-making-line and any code after that will not be executed.
In your case, you could have printed "This was not what I expected, whatever, lets move on!"
Let's say you are connected to database but while reading the records, it throws some exception. Now in this particular case, you can close the connection in Finally block. You just avoided memory leak here.
What I meant to say is , you can perform your task even if exception is thrown by catching and handling it.
In the example you've given, you're right, there is no benefit.
You should only catch an exception if either
You can do something about it (report, add information, fix the situation), or
You have to, because a checked exception forces you to
Usual "handling" of an exception is logging the situation to a log file of your choosing, adding any relevant context-sesitive information, and letting the flow go on. Adding contextual information benefits greatly in resolving the issue. So, in your example, you could have done
public static void main(String[] args) {
try {
System.out.println(str.length());
} catch(NullPointerException npe) {
System.err.println(
"Tried looking up str.length from internal str variable,"
+" but we got an exception with message: "
+ npe.getMessage());
npe.printStackTrace(System.err);
}
}
when looking a message like that, someone will know based on the message what went wrong and maybe even what might be done to fix it.
If you are using Exception, don't
catch(NullPointerException npe) {
npe.printStackTrace();
}
simply
catch(NullPointerException npe) {
//error handling code
}
You are menat to remove error printing. And anyways catch general exception not just specific ones.
If you look at the two exceptions, they are actually different. The first one is referring to line 22, while the second one is referring to line 9. It sounds like adding the try/catch caught the first exception, but another line of code also threw an exception.
Consequently, the exception is being thrown because you never created a new String, or set a value to the string, unless it was done in a part of the code that is not shown.
Adding a try/catch block can be very helpful with objects that you have little to no control over, so if these objects are other than expected (such as null), you can handle the issue properly.
A string is normally something that you would instantiate first, so you shouldn't normally have to worry about using a try/catch.
Hope this helps.
To answer your original question Che, "when to use an exception?"
In Java - I'm sure you've already found out... There are certain methods in Java that REQUIRE the try / catch. These methods "throw" exceptions, and are meant to. There is no way around it.
For example,
FileUtils.readFileToString(new File("myfile.txt"));
won't let you compile until you add the try/catch.
On the other hand, exceptions are very useful because of what you can get from them.
Take Java Reflection for example...
try { Class.forName("MyClass").getConstructor().newInstance(); }
catch ( ClassNotFoundException x ) { // oh it doesnt exist.. do something else with it.
So to answer your question fully -
Use Try/Catch sparingly, as it's typically "frowned on" to EXPECT errors in your application.. on the contrary, use them when your methods require them.

Categories