I'm programming a JavaScript application which accesses some C++ code over Google's V8.
Everything works fine, but I couldn't figure out how I can throw a JavaScript exception which can be catched in the JavaScript code from the C++ method.
For example, if I have a function in C++ like
...
using namespace std;
using namespace v8;
...
static Handle<Value> jsHello(const Arguments& args) {
String::Utf8Value input(args[0]);
if (input == "Hello") {
string result = "world";
return String::New(result.c_str());
} else {
// throw exception
}
}
...
global->Set(String::New("hello"), FunctionTemplate::New(jsHello));
Persistent<Context> context = Context::New(NULL, global);
...
exposed to JavaScript, I'ld like to use it in the JavaScript code like
try {
hello("throw me some exception!");
} catch (e) {
// catched it!
}
What is the correct way to throw a V8-exception out of the C++ code?
Edit: This answer is for older versions of V8. For current versions, see Sutarmin Anton's Answer.
return v8::ThrowException(v8::String::New("Exception message"));
You can also throw a more specific exception with the static functions in v8::Exception:
return v8::ThrowException(v8::Exception::RangeError(v8::String::New("...")));
return v8::ThrowException(v8::Exception::ReferenceError(v8::String::New("...")));
return v8::ThrowException(v8::Exception::SyntaxError(v8::String::New("...")));
return v8::ThrowException(v8::Exception::TypeError(v8::String::New("...")));
return v8::ThrowException(v8::Exception::Error(v8::String::New("...")));
In last versions of v8 Mattew's answer doesn't work. Now in every function that you use you get an Isolate object.
New exception raising with Isolate object look like this:
Isolate* isolate = Isolate::GetCurrent();
isolate->ThrowException(String::NewFromUtf8(isolate, "error string here"));
Related
Recently i have been using GraalVm to execute javascript files from java.
I have the need to reimplement the print() function but i didn't figure out how.
I tried messing with some Bindings's methods and GraalJSScriptEngine's methods, but i didn't get what i was looking for.
Then how can i achieve this?
Note: the implementation of the new print() has to be done in java
Ok i found out how to do that.
It was enough to do this:
ScriptEngine engine = ...
engine.put("print", new Function<String, Object>() {
#Override
public Object apply(String msg) {
System.out.println(msg);
return null;
}
});
here is the code
function xyz() {
try {
var a = someexecutions();
handlesuccess(a)
} catch (err) {
handleerror(err)
}
}
this kind of function written any many times in my codebase I want
function xyz() {
try {
var a = someexecutions();
handlesuccess(a)
} catch (err) {
console.log(`function xyz throw ${err} from file ${__fileName}`)
handleerror(err)
}
}
but writing this anywhere is very huge work since there are more than 100 functions so I think if I am able to overwrite the catch function then it will work for me somehow. So is there any way for doing this
No, there isn't. It's part of the language. What you can do:
Use your IDE to search & replace
Put your code inside handleerror function
Hundred instances are not that much, you can do it :)
This is not possible. If handleerror is a globally shared function you may be able to extract the error's context function name through the non-standard stack error property or arguments.callee.
Otherwise you could possibly use a regex-based find and replace or a parser to rewrite the code programmatically.
Is there any way we can call JS function from Kotlin without having WebView in Android?
Let's say as mentioned below I have one JS function helloJS() in test.js file,
test.js:-
function helloJS(){
return "Hello from JS"
}
And now I want to call this function from Kotlin file like
TestClass.kt:-
class TestHello{
fun getHelloFromJS(){
val name = test.helloJS()
}
}
Till now I am using Webview and loading JS file into that and getting result as call back
But, I read that Kotlin is interoperable with JS like Java
So I am curious to know if there is any way we can use that on Android without having webView
This is not possible straight forward but I found one library Execute JavaScript in Android without WebView for achieve this.
Read that blog carefully and follow below step.
Keep your JavaScript file (test.js) in assets folder in android project.
I have converted that code into Kotlin.
CallJavaScript.jks
import org.mozilla.javascript.Context
import org.mozilla.javascript.Function
import java.io.InputStreamReader
object CallJavaScript {
fun callFunction(mContext: android.content.Context): Any? {
var jsResult: Any? = null
val params = arrayOf<Any>("")
// Every Rhino VM begins with the enter()
// This Context is not Android's Context
val rhino = Context.enter()
// Turn off optimization to make Rhino Android compatible
rhino.optimizationLevel = -1
try {
val scope = rhino.initStandardObjects()
// Note the forth argument is 1, which means the JavaScript source has
// been compressed to only one line using something like YUI
val assetManager = mContext.assets
try {
val input = assetManager.open("test.js")
val targetReader = InputStreamReader(input)
rhino.evaluateReader(scope, targetReader, "JavaScript", 1, null)
} catch (e: Exception) {
e.printStackTrace()
}
// Get the functionName defined in JavaScriptCode
val obj = scope.get("helloJS", scope)
if (obj is Function) {
// Call the function with params
jsResult = obj.call(rhino, scope, scope, params)
// Parse the jsResult object to a String
val result = Context.toString(jsResult)
}
} finally {
Context.exit()
}
return jsResult
}
}
Add this line to build.gradle:
implementation 'org.mozilla:rhino:1.7R4'
In your assets folder, create a file called test.js:
function helloJS()
{
return "Hello from JS";
}
Now simply call above function from Activity.
Log.e("JS : ", CallJavaScript.callFunction(this).toString());
Output :
E/JSĀ :: Hello from JS
It's not possible. You must not confuse the language with the platform.
Kotlin is interoperable with JS like Java
means Kotlin/JS can use and be used in a Javascript platform (Node.js or browsers). The Kotlin code compiled (transpiled) into js is able to call other js files. And external Js code can call the js code build from Kotlin. This is the interoperability with JS.
There is no interoperability between Kotlin/JS and Kotlin/JVM.
Kt looks like JS, but it is not. It will be compiled for Android runtime, not for the java script engine.
JS code require a JS runtime, but it is not in Android Runtime.
i.e. you cannot run JS directly in Java / Kt code for Android.
Am not a pro in Kotlin but Java is a pie for me. Anything you can implement in Java can be implemented in Kotlin and To execute Javascript code, I use rhino which does the job pretty easier than using the webview
Implement it:
try {
Scriptable scope = rhino.initStandardObjects();
rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);
Object obj = scope.get(functionNameInJavaScriptCode, scope);
if (obj instanceof Function) {
Function jsFunction = (Function) obj;
// Call the function with params
Object jsResult = jsFunction.call(rhino, scope, scope, params);
// Parse the jsResult object to a String
String result = Context.toString(jsResult);
}
}finally {
Context.exit();
}
I am updated my durandal SPA application from VS_2012 to VS_2015 with TypeScript 1.8 which will generate JavaScript (ECMA5). I resolved all build errors.But I am unable to fix one typescript error called
"A 'return' statement can only be used within a function body"
I am working on view models. So I need return statement out side of function.
Due to build error I am not able to generate my java-script.
Below is my sample code in Type script:
class typescript1_8{
constructor(){
}
}
return new typescript1_8();
Java Script code needs to generate like below:
var typescript1_8 = (function () {
function typescript1_8() {
}
return typescript1_8;
}());
return new typescript1_8();
Note: I need return statement outside of class. It shouldn't throw any error in Type script as mentioned on above.
You cannot just return something from empty space, you can use Self-invoking function
(function() {
return new typescript1_8();
})();
I am newbie in rhino.
Currently, I am using Rhino 1.7R framework thru .NET 4 and IKVM.NET.
I exposed several wrapped classes implementing NativeJavaObject using setWrapFractory() API.
public class InterceptNativeObject : NativeJavaObject
{
public InterceptNativeObject()
{
}
public override Object get(String name, Scriptable start)
{
Object res = base.get(name, start);
if (res is NativeJavaMethod)
{
NativeJavaMethod method = (NativeJavaMethod)res;
return new RhinoMethodWrapFunction(method);
}
if (res == org.mozilla.javascript.UniqueTag.NOT_FOUND &&
base.javaObject is IPropertBox && base.javaObject != null)
{
object ret = ((IPropertBox)base.javaObject)._x__GetPropertyValue(name);
return Utils.ConvertCLRValueToJavaValue(ret);
}
return res;
}
.....
}
Now, I can access all .NET methods and properties as I wanted.
My current problem is to support 'for...in' my NativeJavaObject classes.
When I evaluate
'for(var prop in myClass){printf(prop);};' ,
it returns 'no 'in' call for non-object' error.
It seems the 'get' attempting to searching an object of ' _iterator_', but it resulted in 'not found' at get() function. So, it ends up with exception.
So far, I tried
added java.util.iterator
return this.getIds().GetEnumrator();
None of works.
How can i allow property enumrate access for my Wrapped NativeJavaObject?
What is Rhino's expected return value of ' _iterator_' to enable 'for...in'?
Thanks in advance!
__iterator__ is part of a Mozilla specific language extension. That link explains that the __iterator__ method returns an object with a next method that throws StopIteration when the iterator is exhausted.
You have to opt in to iterators and generators though:
To enable JavaScript 1.7 support, you must set the version as 170 using the Context.setLanguageVersion() API call. If you are using the Rhino shell, you can specify -version 170 on the command line or call version(170) in code executed by the shell.
You can write JS in rhino that will wrap a Java iterator to present it as a JS iterator:
function javaIteratorToJsIterator(javaIterator) {
return {
next: function () {
if (!javaIterator.hasNext()) { throw StopIteration; }
return javaIterator.next();
}
};
}
Alternatively, you can use Mozilla style generators but I think you need to create the Rhino interpreter with an option to enable them.
While custom iterators are a useful tool, their creation requires careful programming due to the need to explicitly maintain their internal state. Generators provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function which can maintain its own state.
A generator is a special type of function that works as a factory for iterators. A function becomes a generator if it contains one or more yield expressions.