How can I access properties of Java Objects passed to scriptEngine? - javascript

I am passing an object to a scriptEngine using the engine.put() method, and am attempting to retrieve a property of said object using the engine.eval() method. However I can't seem to access them as the object seems to lose its methods when put in the engine, and the get() method I'd normally use in Javascript also seems to fail.
try {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
engine.put("transformContext",transformContext);
engine.put("dataRecordsByName",transformContext.getDataRecordsByName());
//These three all return what I'm expecting - 2x the whole object and then just dataRecordsByName property
System.out.println(engine.get(transformContext));
System.out.println(engine.eval("print(transformContext"));
System.out.println(engine.get(dataRecordsByName));
//These throw errors get() and getDataRecordsByName() seemingly do not exist for transformContext in the engine
System.out.println(engine.eval("print(transformContext.getDataRecordsByName())"));
System.out.println(engine.eval("print(transformContext.get('dataRecordsByName'))"));
}catch(Exception e){
System.err.println("Error evaluating script: "+e.getMessage());
}
I have read that scriptEngine only imports public methods from public classes. In this case though TransformContext is public as are all its methods, so that should be fine?
Any help understanding this or a solution would be appreciated.

After some further research it seems that graal.js does not map properties as you may expect by default, but can do so if you run it in nashorn compatability mode.
System.setProperty("polyglot.js.nashorn-compat", "true");
After doing this, you can retrieve the object properties as you normally would in JavaScript:
engine.eval("console.log(transformContext.dataRecordsByName)");
Thanks to the guys on this thread:
https://github.com/oracle/graaljs/issues/169

Related

Why can't I access my custom string prototype from an object method?

I have a custom string prototype that does some actions to a string;
String.prototype.norm_to_ascii=function(){return unescape(encodeURIComponent(this))};
In my example, the string that I want to apply the prototype to is a global object property that lives outside of the SampleObject object. In my actual code it would be referenced like this;
var userObject = {
name: "SomeName",
id: "SomeID"
}
It works everywhere in my project (other js files) except for within a particular Object method;
var SampleObject = { //This is in it's own js file called sampleobject.js
test: 0,
doStringThings {
let something = userObject.id.norm_to_ascii() //RETURNS userObject.id.norm_to_ascii is not a function
}
}
So in the SampleObject, I need to use the id, for example, but I need to do some basic decoding of the id value that is in the userObject which is what the string prototype does.
I can use this string prototype elsewhere. This is in a chrome extension so I have defined the prototype in the service worker and it can be used in the popup and content pages as well as the service worker so it must have to do with the object method but I can't figure out why?
Can anyone offer any suggestions to expose that prototype to the object method without having to redefine it?
EDIT
I should have been more clear in my explanation. I updated my example above.
You forget about this
this.otherTestValue.norm_to_ascii()
After seeing the updated question my conclusion is that you are defining the norm_to_ascii function after you run it.
Changing the order of the imports should fix the problem. Can you show us the structure of the project and where are you importing the file with that prototype?

Send Object from Javascript to Kotlin using Webview

I have loaded a webpage using WebView component and added a JavascriptInterface. Please check the code below,
val webview = WebView(this)
setContentView(webview)
webview.settings.javaScriptEnabled = true
webview.loadUrl(HOME_PAGE_URL)
webview.addJavascriptInterface(JavascriptInterface(),”javascript_bridge”)
And when I call the invoke from Javascript using window.javascript_bridge.showToast(“Information Saved”);
private inner class JavascriptInterface
{
#android.webkit.JavascriptInterface
fun showToast(text: String?)
{
Log.d("WEBVIEW", text);
}
}
I am able to call the method from Javascript to Kotlin without any trouble.
But now I want to pass an Object from Javascript to Kotlin like below,
var info = {
message: “Information Saved”,
ID: 123456
}
And when I call the invoke from Javascript using window.javascript_bridge.showToast(info);
I tried to change to the data type to Any, but the value passed from Javascript is null
private inner class JavascriptInterface
{
#android.webkit.JavascriptInterface
fun showToast(text: Any?)
{
Log.d("WEBVIEW", text.toString());
}
}
As far as i know, the javaScript interface methods only accepts primitive types of data as parameters (as discussed on this question).
If you still want to achieve that, you may serialize the object (to JSON format, for instance) in the javaScript and then Deserialize it in Java.
Hope it helps :)

How to cast an Object from Javascript to a class?

I have the following ActionScript code :
import flash.external.*
public function req(temp:Object):void{
var request:URLRequest=temp as URLRequest; // request is then null
}
ExternalInterface.addCallback('call',req);
and the follwing JavaScript code
document.getElementById('flash').call(({url:"http://ytrezq.sdfeu.org/flashredirect/?https://chromium-review.googlesource.com/accounts/self/profile",digest:null,method:"DELETE",requestHeaders:null,data:null,contentType:null}));
Or is it possible to cast the Javascript object to Urlrequest from JavaScript ? If not, how to do it from ActionScript ?
Please note I’m not interested in keeping the Original JavaScript Object…

Calling javascript function in c++ with emscripten embind

This question comes in two parts. What I want to do is to put most of my program logic in c++ classes and some view related function in js (like DOM manipulation and styling.) I use emscripten embind the classes and it works fine while I don't know how to interact with the js code (there are really limited resources on their tutorial.)
I was thinking to pass a val object to the c++ class according to their tutorial (https://github.com/kripken/emscripten/wiki/Tutorial) The passing works just fine while the "call" function doesn't work. I got a compile time error.
Here is the example I tried which they put on their tutorial:
#include <emscripten/val.h>
using namespace emscripten;
int main(){
val Math = val::global("Math");
Math.call("abs",-10);
return 0;
}
and I got the following errors:
error: no matching member function for call to 'call'
Math.call("abs",-10);
~~~~^~~~
emscripten/1.5.6/system/include/emscripten/val.h:247:21: note: candidate template ignored: couldn't infer template argument 'ReturnValue'
ReturnValue call(const char* name, Args&&... args) const {
Basically it says the the compiler doesn't know the return type of the "call" function.
Did I do anything wrong or is there a better way to interact with js code?
Thanks,
yi
That's a common C++ problem. As a general rule, the following message should always make you double check in C++:
note: candidate template ignored: couldn't infer template argument 'ReturnValue' ReturnValue call(const char* name, Args&&... args) const
This mostly means that you tried to call a templated function but did not specify the necessary types.
If you look at the signature (in system/include/emscripten/val.h):
template<typename ReturnValue, typename... Args>
ReturnValue call(const char* name, Args&&... args) const
While it can infer Args quite fine, it has no idea, what ReturnValue might be. So calling this function should be done via e.g.:
Math.call<int>("abs",-10);

Does Awesomium allow me to call/use C++ variables/methods in JS?

Awesomium easily allows for C++ code to call Javascript methods, but I haven't found a definite answer as to if it can do the opposite. This site seems to say that you can, but looking through the text and examples doesn't enlighten me.
So, I'm looking for a definite answer: can I call C++ variables/methods in my Javascript(Jquery), or not?
If you could include a simple example, that would be extremely appreciated as well.
Thank you!
You definitely can-- you'll just need to build an extra layer on top of WebView::setObjectCallback and WebViewListener::onCallback using delegates/function-pointers.
I wrote a quick JSDelegate.h class (view it here) that you can use to hookup "onCallback" events directly to C++ member functions.
The basic idea is to maintain a mapping of callback names to delegates:
typedef std::map<std::wstring, Awesomium::JSDelegate> DelegateMap;
DelegateMap _delegateMap;
And call the corresponding function from your WebViewListener::onCallback:
void MyListener::onCallback(Awesomium::WebView* caller, const std::wstring& objectName,
const std::wstring& callbackName, const Awesomium::JSArguments& args)
{
DelegateMap::iterator i = _delegateMap.find(callbackName);
if(i != _delegateMap.end())
i->second(caller, args);
}
And then, each time you wish to bind a specific C++ function, you would do it like so:
// Member function we wish to bind, must have this signature for JSDelegate
void MyClass::myFunction(Awesomium::WebView* caller, const Awesomium::JSArguments& args)
{
// handle args here
}
// Instantiate MyClass instance in C++
MyClass* myClass = new MyClass();
// Create corresponding 'MyClass' object in Javascript
webView->createObject(L"MyClass");
// Do the following for each member function:
// Bind MyClass::myFunction delegate to MyClass.myFunction in JS
_delegateMap[L"myFunction"] = Awesomium::JSDelegate(myClass, &MyClass::myFunction);
webView->setObjectCallback(L"MyClass", L"myFunction");
Then, you should be able to call MyClass::myFunction directly from Javascript like so:
MyClass.myFunction("foo", 1, 2 3)
Hope this helps! I haven't tested any of the code but I wrote it with Awesomium v1.6 RC4 SDK in mind.

Categories

Resources