Can I throw exception based on method signature in ASM? - java

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.

Related

Java: Is There Any Way to Specify When an Exception Will be Thrown?

I have code something like this pseudo code:
void doSomething(int data) throws Exception{
if(data < 10) throw new Exception("Exception thrown"); // throws an exception based on a condition
else { ... } // logic goes here
}
When I try to call doSomething in the main function, it give me an error:
public static void main(){
doSomething(11); // Error! unreported exception
}
Here is a link to the previous example.
So I have to do one of the following:
Add a try catch block around every doSomething call
Add a throws statement in main
Get rid of the throws statement in doSomething
Make the condition a precondition, so that not following it results in undefined behavior or something similar.
3 will not work, because doSomething may throw an exception when a client is using it.
1 and 2 are simply redundant, and I think they should be avoided.
Finally, 4 is the most appealing to me (being primarily a C++ coder) but runs contrary to Java programming.
My question is: What is the best way out of the mentioned options (or any other options), and what is the best way to implement it?
It really depends on the context You are working with.
If You want the code to stop executing at the moment the Exception is thrown, You could use Runtime exceptions, You don't have to catch them.
The good use case would be a REST endpoint. If something goes wrong during the computation of the response, we could throw ResponseStatusException - the Runtime exception which would immedeately return the Http Response Error to the client and stop any further execution of the code.
In contrary, if You have a logic which has to be executed even if the exception was thrown, the best way would be to use try - catch blocks, or to add throws statement to the method declaration and try - catch in parent method.

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.

Get Nashorn script line number during interpretation

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.

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:

Exception handling in this scenario

Trying my hands on Java for the first time, please be kind. I have following code in a Web Controller where a service is called based on enclosed Switch-Case statement.
Issue I am facing is, if the service call throws an Exception, this exception gets shown on the JSP page. Basically the code never reaches the lines:
if(!statusFlag)
{
model.addAttribute("statusFlag", statusFlag);
return "myJspPage"
}
How do I make sure the executing goes to above lines, even though an exception is thrown in the WebService call at:
statusFlag = myWebService.getMeStatus();
Should I enclose the whole Switch Statement inside try-catch block?
Snippet:
#Controller
public String mySpringController() throws Exception
{
//rest of the controller code
switch ( condition )
{
case MAY :
statusFlag = myWebService.getMeStatus();
if(!statusFlag)
{
model.addAttribute("statusFlag", statusFlag);
return "myJspPage"
}
break;
case JUNE :
statusFlag = myWebService.getMeStatus();
if(!statusFlag)
{
model.addAttribute("statusFlag", statusFlag);
return "myJspPage"
}
break;
case JULY :
statusFlag = myWebService.getMeStatus();
if(!statusFlag)
{
model.addAttribute("statusFlag", statusFlag);
return "myJspPage"
}
break;
default:
//Do something by default.
}
return "myJspPage";
}
If that line is throwing an Exception it means that it is never returning, so statusFlag is still with its original value and the execution of that method has stopped. You need to surround it in a try - catch if you want to catch the Exception and do something about it.
I see you are using Spring. In Spring Controllers you can also have your own special methods which get invoked when an Exception occurs. Using the #ExceptionHandler annotation.
I don't see the purpose of your switch statement since each case does the same thing.
But basically you can put your webservice call in a try-catch block
try{
webservice.call();
}
catch (Exception e){
// handle the exception
}
finally{
//anything in here will be executed regardless if an exception is caught or not
}
You're writing Java in the style of C++, where you're returning error codes and then checking them to determine whether anything went wrong. There are a number of issues with this snippet, but the reason for the exception display is that you never catch the exception that's being thrown. Where you should put your try-catch block depends on what the exception means; if it's something that isn't specific to a particular month, then yes, enclose the entire switch statement to share the error handling.
As an aside, did you copy and paste your actual code, or did you try to retype an example? Those case blocks all look identical.

Categories