I need to call a Java method from Javascript. So I defined the method:
private native void registerMethod() /*-{
var self = this;
$wnd.test = function(longParam) {
self.#mypackage.HomeView::test(Ljava/lang/Long;)(longParam);
};
}-*/;
The Java method:
private void test(Long longParam) {
GWT.log("Call to test with longParam = " + longParam);
}
The JS call:
public static native void paypalClose() /*-{
$wnd.alert(top.test);
top.test(10);
top.dgFlow.closeFlow();
top.close();
}-*/;
The alert shows the Javascript function definition. If I call top.test(), it works but no param is passed. But if I call top.test(10) I get a null alert window.
Your method excepts a java.lang.Long, not a long, so you have to create an instance of Long. You could use #java.lang.Long::new or #java.lang.Long::valueOf, except you cannot use longs either in JSNI: https://developers.google.com/web-toolkit/doc/latest/DevGuideCodingBasicsJSNI#important
Because JavaScript numbers are strictly equivalent to Java doubles, you should use a double or java.lang.Double as an argument. Once in the Java world, you can cast the double to a long if you like, but not from/in JSNI.
Related
I have a pojo in my class containing some methods to manipulate Maps and Arrays in java. This object is used in RPC calls to carry my configurations. I have a mechanism in which before making any RPC call I execute a javascript function. Now what I really want is to pass my configuration object to this javascript function and this javascript function can manipulate this configuration object and finally this manipulated object will be passed in my RPC call.
So how can I pass my java object to javascript and allow manipulating it?
First, you cannot manipulate Java objects from javascript directly. But what you can do, is to export a set of static methods to javascript and use them to manipulate your objects. This is done in this way:
public void onModuleLoad() {
exportHelloMethod(this);
}
public String exportedMethod(String name) {
// Manipulate your java classes here
// return something to JS
}
// Create a reference in the browser to the static java method
private native void exportHelloMethod(HelloClass instance) /*-{
$wnd.hello = instance#[...]HelloClass::exportedMethod(Ljava/lang/String;);
}-*/;
Fortunately there is a library which allows exporting java methods and classes in a simpler way. It is gwt-exporter, and you have just to implement Exportable in your class and use a set of annotations so as the exporter generator does all the work.
#ExportPackage("jsc")
#Export
public class MyClass implements Exportable {
public void show(String s){
}
}
public void onModuleLoad() {
ExporterUtil.exportAll();
}
Then in javascript you can instanciate and manipulate the class:
var myclass = new jsc.MyClass();
myclass.show('whatever');
I am trying to implement an API (SCORM API) using GWT.
The client code expects an API object with methods like Initialize(), getLastError() and so on...
I tried to implement this api as an Java Object, but i see that the compiled names are changed and cannot be used directly by client code.
I see that gwt-exporter can do the trick (http://code.google.com/p/gwt-exporter/) but i would like to know how to do it using pure gwt and jsni.
As the API is expected as a object, named API_1484_11 attached to the window object, not an function, , i don't see how to use the $entry() idiom.
Here is my current, failing, code:
public final class SCORMApi {
protected SCORMApi() {}
public void Initialize(){
GWT.log("** INITIALIZE CALLED **");
}
public static void create(){
bind(new SCORMApi());
}
public static native void bind(SCORMApi api) /*-{
$wnd.API_1484_11 = api;
}-*/;
}
So, in this context, my question is:
How can i get javascript calls (e.g. window.API_1484_11.Initialize() ) to reach my java gwt code?
You're on the right lines with your bind method. But you haven't understood how to call Java methods from within JSNI. This is how you do it in the case of your Initialize method:
public static native void bind(SCORMApi api) /*-{
$wnd.API_1484_11 = {
initialize: function() {
$entry( api.#com.yourpackage.name.SCORMApi::Initialize()() );
}
};
}-*/;
The blogs Getting To Really Know GWT parts 1 and 2 are required reading on this subject.
I'm working with the google maps api, I'd like to create an instance of one of their objects:
public static final native void test(double lat, double lng) /*-{
var obj = new google.maps.LatLng(lat, lng);
}-*/;
but the above does not work, prints the following error:
com.google.gwt.core.client.JavaScriptException: (ReferenceError)
#com.google.gwt.core.client.impl.Impl::apply
(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)
([JavaScript object(4), JavaScript object(3), JavaScript object(6)]):
google is not defined
so I probably have to explain to GWT what the "google.maps.LatLng" object is - how do I do that? I thought there was a specific syntax for that, but can't seem to find it anymore in the docs,
Thanks
If you define google.maps somewhere else in your host page, you must prefix it with $wnd in your GWT code:
public static final native void test(double lat, double lng) /*-{
var obj = new $wnd.google.maps.LatLng(lat, lng);
}-*/;
From GWT documentation:
When accessing the browser's window and document objects from JSNI,
you must reference them as $wnd and $doc, respectively. Your compiled
script runs in a nested frame, and $wnd and $doc are automatically
initialized to correctly refer to the host page's window and document.
I am going to file this as a bug report, but I wanted to check if someone here can see something wrong with what I am doing.
When you expose an instance method from a GWT class through JSNI, this works as expected in JavaScript. Since we are cross compiling Java, I would instead expect this to be bound to the instance automatically. For example:
package com.test;
class Foo {
public void instanceFunction() {
this.otherFunction() // will cause an error when called from JSNI!
}
public void otherFunction() {
// does some stuff
}
public native JavaScriptObject getInstanceFunction() /*-{
return this.#com.test.Foo::instanceFunction();
}-*/;
}
Currently the workaround is to bind the function yourself (not very portable):
public native JavaScriptObject getInstanceFunction() /*-{
return this.#com.test.Foo::instanceFunction().bind(this);
}-*/;
This can also be seen as preference, some may prefer that the functions remain unbound. I would say the current functionality is unintuitave and unnecessary. I cannot imagine a use case for having an unbound this directly in Java code. Also, some browsers do not implement bind(1), so my workaround is not robust.
If you want a portable bind, it's as easy as:
var that = this;
return $entry(function() {
return that.#com.test.Foo::instanceFunction()();
});
An external javascript gives a number that should be handed over to Java method named mycallback.
I have defined:
Java:
class MyClass {
public static void mycallback(JavaScriptObject number) {
// do something with the number
}
}
Javascript:
$wnd.callback = $entry(#com.package.MyClass::mycallback(Lcom/google/gwt/core/client/JavaScriptObject));
And the Javascript call is:
$wnd.callback(number_from_external_javascript);
But I get error:
JS value of type number, expected com.google.gwt.core.client.JavaScriptObject
And my ultimate goal is to have a java method with parameter type of Integer, not of JavascriptObject. I just thought GWT should wrap javascript objects in JavascriptObject, but it seems it won't.
GWT version is 2.4.
GWT will automatically cast a JS Number value to any Java number primitive type (int, double, etc.), JS String to Java String, and JS Boolean to Java boolean. It'll never pass them as JavaScriptObjects.
If the number cannot be null, then just declare your callback with an int argument. If it can be null, then you'll have to explicitly create an Integer instance, something like:
$wnd.callback = $entry(function(n) {
if (number != null) {
// box into java.lang.Integer
number = #java.lang.Integer::valueOf(I)(n);
}
#com.packge.MyClass::mycallback(Ljava/lang/Integer;)(number);
});
Alternatively, I think you can pass a JS number as a JavaScriptObject if it's a Number object rather than a Number value, so this might work:
$wnd.callback = $entry(function(n) {
n = new Number(n); // "box" as a Number object
#com.packge.MyClass::mycallback(Lcom/google/gwt/core/client/JavaScriptObject;)(n);
});
What about using the gwt-exporter generator to expose your gwt code to js, so you dont have to deal with jsni and you could benefit of the nice features it has (complex objects, arrays, closures, overlays, doclet, etc)
Using gwt-exporter your class just have to implement Exportable and use an annotation to expose your method.
public static class MyClass implements Exportable {
#Export("$wnd.mycallback")
public static void mycallback(long number) {
Window.alert("" + number);
}
}
Add this line to your onmoduleload and leave the compiler to do the work
public void onModuleLoad() {
ExporterUtil.exportAll();
}
Then you can use the method as you said
<script>
window.mycallback(1234)
</script>