How can I call from external JS with JSNI?
For example:
//Some external JS code
...
this.onFeatureClick = function(event) {
...
var name = "Batman";
passToJava(name); //Invoke java method and pass String name
};
I tried this here:
public void onModuleLoad() {
...
nativeVariableName(); //Call native method
}
public static void passToJava(String name) {
System.out.println(name);
}
public native String nativeVariableName() /*-{
$wnd.passToJava = function(name) {
#com.google.myproject.webinterface.client.MyWebInterface::passToJava(Ljava/lang/String;)(name);
}; }-*/;
I don't even know if the call from JavaScript works.
Thanks.
This code works just fine. I don't know where do you expect to see result of invocation of System.out.println, but looks like you are looking into wrong place. Replace System.out.println with Window.alert and see for yourself. If it doesn't work, it means that error is in some other place:
Check if the function is correctly exposed (open console in browser,
and type window.passToJava, if it displays null, function wasn't
exposed)
Check if onFeatureClick is called correctly.
Related
I am learning GWT, I am trying following example in which I have tried to pass the JSON object in java function.
public class HomeController implements EntryPoint {
public void onModuleLoad() {
createTestNativeFunction();
Presenter presenter = new PersenterImpl();
presenter.go(RootPanel.get());
}
public native void createTestNativeFunction()/*-{
parser: function() {
var that = this;
var jsonResult = JSON.parse({id:42,name:'yo'});
return this.#com.easylearntutorial.gwt.client.HomeController::onParse(Lorg/sgx/jsutil/client/JsObject;)(jsonResult);
}
void onParse(jsonResult){
System.out.println(jsonResult);
}
}
}-*/;
}
I am getting following errors:
Tracing compile failure path for type 'com.easylearntutorial.gwt.client.HomeController'
[ERROR] Errors in 'file:/C:/Users/ameen/workspace/Tutorial/src/com/easylearntutorial/gwt/client/HomeController.java'
[ERROR] Line 31: missing ; before statement
void onParse(jsonResult){
--------------------------------^
[ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
[WARN] Server class 'com.google.gwt.dev.shell.jetty.JDBCUnloader' could not be found in the web app, but was found on the system classpath
[WARN] Adding classpath entry 'file:/C:/Program%20Files/gwt-2.7.0/gwt-dev.jar' to the web app classpath for this session
For additional info see: file:/C:/Program%20Files/gwt-2.7.0/doc/helpInfo/webAppClassPath.html
You really should try to avoid JSNI. You can probably write 99% of your code not using JSNI at all. If you really need it, you should use the new JsInterop instead, documentation still in early stage but you can see this documentation here.
If you need to use JsInterop or JSNI it is usually because you need to wrap a JS lib, so first, try to find if it is already wrapped. If it is not you can always use some other wrapper library to learn how to wrap your JS lib.
OpenLayers JsInterop wrapper https://github.com/TDesjardins/gwt-ol3
OpenLayers JSNI wrapper (deprecated) https://github.com/geosdi/GWT-OpenLayers
Or explore github https://github.com/search?q=topic%3Agwt+topic%3Ajsinterop
System.out.println() is a java function, you are looking for console.log().
The body of the native is JavaScript, not Java.
You are declare you variable jsonResult into your parser: function(), jsonResult only exist into that function. Thats why the system say you that
missing ; before statement
Because you never declare the varieble into createTestNativeFunction().
Plus sjakubowski is right System.out.println() is a java function, you need to use console.log() on JavaScript.
Try this:
public native void createTestNativeFunction(){
var jsonResult = {};
parser: function() {
var that = this;
jsonResult = JSON.parse({id:42,name:'yo'});
return this.#com.easylearntutorial.gwt.client.HomeController::onParse(Lorg/sgx/jsutil/client/JsObject;)(jsonResult);
}
void onParse(jsonResult){
console.log(jsonResult);
}
}
I did the following to solve my errors.
public class HomeController implements EntryPoint {
public void onModuleLoad() {
createTestNativeFunction();
Presenter presenter = new PersenterImpl();
presenter.go(RootPanel.get());
}
// var jsonResult = JSON.parse({id:42,name:'yo'});
public native void createTestNativeFunction()/*-{
var that = this;
$wnd.testFunction = function(jsonResult) {
that.#com.easylearntutorial.gwt.client.HomeController::onParse(Lorg/sgx/jsutil/client/JsObject;)(jsonResult);
};
}-*/;
public void onParse(JsObject jsonResult){
int i =42;
}
}
I am creating cordova application witch are showing call logs, so i make plugin and i get calls log in native java code and i don`t know how to pass it back to index.html.
this is my plugin javascript
navigator.callslog= {};
navigator.callslog.show = function () { cordova.exec (null, null, "callslog", "show", []);};
And this is java code for my plugin
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
{
if (action.equals("show")) {
// get call logs
String calls = getCallDetails(callbackContext);
callbackContext.success();
Log.v("Calls", calls);
this.webView.postMessage("callsLog", "show");
} else {
return false;
}
callbackContext.success();
return true;
}
And in index.js i call plugin and data was printed in logcat it works but i don`t know how to get the data and represent in index.html
onDeviceReady: function() {
app.receivedEvent('deviceready');
console.log('Recevedod event ');
var callsLog= navigator.splashscreen.show();
}
Thank you guys
In this first parameter is success call back and second one is fail callback.
instead of null and null
you have to do like this
navigator.callslog.show = function () { cordova.exec (successcb, failcb, "callslog", "show", []);};
function successcb(s){
console.log(s);//what you passed from Java code
}
function failcb(e){
console.log("Err cb");
}
Pass string as an argument for callbackContext.success() method as
callbackContext.success(calls);
There is a BookView.class that has a private method defined as below
public class BookView{
private boolean importBook(String epubBookPath){
//The function that adds books to database.
}
}
I am trying to call this function from a different package. My code is
protected void onPostExecute(String file_url) {
// dismiss the dialog after the file was downloaded
dismissDialog(progress_bar_type);
/*Now we add the book information to the sqlite file.*/
TextView textView=(TextView)findViewById(R.id.textView1);
String filename = textView.getText().toString();
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String epubBookPath = baseDir+filename;
Log.i("epubBookPath:",epubBookPath); //No errors till here!
try {
Method m=BookView.class.getDeclaredMethod("importBook");
m.setAccessible(true);//Abracadabra
//I need help from here! How do i pass the epubBookPath to the private importBook method.
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Intent in = new Intent(getApplicationContext(),
CallEPubUIActivity.class);
startActivity(in);
}
EDIT:
I found another public method in the jar file which is doing the above work.
public void jsImportBook(String epubBookPath) {
if (!BookView.this.importBook(epubBookPath))
return;
BookView.this.createBookshelf();
}
If you want to do that you should make it public or make a public wrapper method it.
If thats not possible, you can work your way around it, but thats ugly and bad and you should have really good reasons to do so.
public boolean importBook(String epubBookPath){
//The function that adds books to database.
}
or
public boolean importBookPublic(String epubBookPath){
return importBook(epubBookPath);
}
private boolean importBook(String epubBookPath){
//The function that adds books to database.
}
Also note that if you CAN'T access the method directly in a third-party library than it is most likely INTENDED that way. Take a look at the call hierarchy of the private method and see if you find a public method that does the call to the private one and that also does what you need.
Libraries are often designed in a way that a public method does some checking (all Parameters given, authenticated etc.) and then pass the call to the private method to do the actual work. You almost never want to work around that process.
With reflection, you'll need an instance of BookView to invoke the method with (unless it's a static method).
BookView yourInstance = new BookView();
Method m = BookView.class.getDeclaredMethod("importBook");
m.setAccessible(true);//Abracadabra
Boolean result = (Boolean) m.invoke(yourInstance, "A Path"); // pass your epubBookPath parameter (in this example it is "A Path"
The method you are looking for is Method#invoke(Object, Object...)
Use reflection to get you method and set Accessible as true, then invoke the method using BookView Object instance and required parameters(path string) using statement as below:
Boolean result = (Boolean)method.invoke(bookObject, epubBookPath);
Sample code as below:
Method method = BookView.getDeclaredMethod("importBook");
method.setAccessible(true);
Boolean result = (Boolean)method.invoke(bookObject, epubBookPath);
Private methods cannot be accessed outside the class it is defined.
Make it Public.
I need to pull a JavaScript var off a site so I can use it in my code. Following this tutorial, I was able to display the string in an alert message. But what do I have to do to use the string outside of the alert message? Thanks.
EDIT: My code is basically the same as in the tutorial.
Instead of calling AlertDialog, just do something in Java with the value of the "html" parameter, unless I'm completely misunderstanding what you are asking.
String savedHtml = null;
/* An instance of this class will be registered as a JavaScript interface */
class MyJavaScriptInterface
{
#SuppressWarnings("unused")
public void showHTML(String html)
{
savedHtml = html; // this ought to work.
}
}
I'm developing an invisible Java Applet, that will be controlled entirely from JavaScript.
I can call the applet's Java methods easily, and I can call JavaScript methods from within the applet by using netscape.javascript.JSObject.getWindow(this).call().
But in order to register a JavaScript callback in the applet, I guess I would need an JavaScript function object of some sort.
I would like to do:
public void registerCallback( SomeJavascriptFunction func ) { ... }
Which I could call from Javascript:
myapplet.registerCallback(function(){ alert("called back"); });
So I could call this function in later code:
func.call( ... );
Does something like this exist? How can I do this?
Rigth now I'm thinking of creating some Javascript to handle this callback mechanism instead of doing so from the applet.
I realise this is a really old question, but it ranked 2nd in one of my searches for something else, and I think the below may help someone else that finds this.
I've recently done something similar whereby a Java applet needs to call back into JavaScript on completion of a task, calling different functions on success or error. As has been the trend over recent times, my needs were to call into anonymous functions defined as parameters being passed to other functions. This is the javascript on the client side:
applet.DoProcessing({
success: function(param) {
alert('Success: ' + param);
},
error: function(param) {
alert('Failed: ' + param);
}
});
As mentioned in the other answers, Java can only call into JavaScript methods by name. This means you need a global callback method, which can then call into other methods as need be:
function ProcessingCallback(isSuccessful, cbParam, jsObject) {
if (isSuccessful && jsObject.success)
jsObject.success(cbParam);
else if (!isSuccessful && jsObject.error)
jsObject.error(cbParam);
}
This function is called directly from within the Java applet:
public void DoProcessing(final Object callbacks) {
//do processing....
JSObject w = JSObject.getWindow(this);
//Call our named callback, note how we pass the callbacks parameter straight
//back out again - it will be unchanged in javascript.
w.call("ProcessingCallback", new Object[]{successful, output, callbacks});
}
You could hold on to the reference of the parameter object being passed in indefinitely if you wanted to use it as some form of registered callback rather than a throwaway one if need be etc.
In our case the processing can be time intenstive, so we actually spin up another thread - the callbacks still work here also:
public void DoProcessing(final Object callbacks) {
//hold a reference for use in the thread
final Applet app = this;
//Create a new Thread object to run our request asynchronously
//so we can return back to single threaded javascript immediately
Thread async = new Thread() {
//Thread objects need a run method
public void run() {
//do processing....
JSObject w = JSObject.getWindow(app);
//Call our named callback, note how we pass the callbacks parameter
//straight back out again - it will be unchanged in javascript.
w.call("ProcessingCallback", new Object[]{successful, output, callbacks});
}
}
//start the thread
async.start();
}
I am brand new to Java <-> JavaScript communication, as I planned to explore it this week. A good opportunity here... :-)
After some tests, it seems you cannot pass a JS function to a Java applet. Unless I am doing it the wrong way...
I tried:
function CallJava()
{
document.Applet.Call("Does it work?");
document.Applet.Call(function () { alert("It works!"); });
document.Applet.Call(DoSomething); // A simple parameterless JS function
document.Applet.Call(window.location);
}
function DumbTest(message, value)
{
alert("This is a dumb test with a message:\n" + message + "\n" + value);
}
where Call is (are) defined as:
public void Call(String message)
{
JSObject win = (JSObject) JSObject.getWindow(this);
String[] arguments = { "Call with String", message };
win.call("DumbTest", arguments);
}
public void Call(JSObject jso)
{
JSObject win = (JSObject) JSObject.getWindow(this);
String[] arguments = { "Call with JSObject", jso.toString() };
win.call("DumbTest", arguments);
}
When I pass a JS function (all tests in FF3), I get a null on the Java side.
Note that the following Java routine allows to display the JS code of DumberTest function!
public int Do()
{
JSObject win = (JSObject) JSObject.getWindow(this);
JSObject doc = (JSObject) win.getMember("document");
JSObject fun = (JSObject) win.getMember("DumberTest");
JSObject loc = (JSObject) doc.getMember("location");
String href = (String) loc.getMember("href");
String[] arguments = { href, fun.toString() };
win.call("DumbTest", arguments);
return fun.toString().length();
}
To the point: I made a JS function:
function RegisterCallback(cbFunction)
{
var callback = cbFunction.toString(); // We get JS code
var callbackName = /^function (\w+)\(/.exec(callback);
document.Applet.RegisterCallback(callbackName[1]);
}
I extract the name of the JS function from the toString result and pass it to Java applet. I don't think we can handle anonymous functions because Java call JS functions by name.
Java side:
String callbackFunction;
public void RegisterCallback(String functionName)
{
callbackFunction = functionName;
}
void UseCallbackFunction()
{
if (callbackFunction == null) return;
JSObject win = (JSObject) JSObject.getWindow(this);
win.call(callbackFunction, null);
}
win.eval() will call a predefined javascript.
String callbackFunction;
public void RegisterCallback(String functionName)
{
callbackFunction = functionName;
}
void UseCallbackFunction()
{
if (callbackFunction == null) return;
JSObject win = (JSObject) JSObject.getWindow(this);
win.eval(callbackFunction);
}