The trick with these hook methods is that no code in my GWT application
actually calls them. That's the point, they're being made available
for outside sources to call them. However, when I compile my app, the
unreferenced methods get removed, or don't get compiled.
I've tested this by having the following:
// simple method that is referenced by code in my GWT application
public void gwtReferencedMethod(String arg) {
Window.alert(arg);
}
// simple method that is not referenced in my GWT application
public void unreferencedMethod(String arg) {
Window.alert(arg);
}
When I compile the above code in my application, the
gwtReferencedMethod is compiled into Javascript, but unreferencedMethod
is not compiled into Javascript. However, I can change the code to the
following:
// simple method that is referenced by code in my GWT application
public void gwtReferencedMethod(String arg) {
unreferencedMethod(arg);
}
// simple method that is now referenced in my GWT application
public void unreferencedMethod(String arg) {
Window.alert(arg);
}
When I change to the above code, both methods are compiled into
Javascript. I've tested this several times to be sure my eyes weren't
playing tricks on me.
Is this a "feature" of the GWT Compiler? If so, is it documented
anywhere? Is it done for optimization? Or, for some obscure security
reason? Most importantly, is there a way to turn it off?
----
Greg
It looks like an optimization to reduce the size of the resulting
Javascript code and it makes sense to me. I see your point though. But
how were you going to call GWT methods from you legacy Javascript
code? GWT produces rather obfuscated code by default and to me it will
not be easy to even find the needed methods there. You can tell the compiler
to generate more readable output, but that will dramatically increase
the size of your client side code.
Regards,
Roman
However, we knew that people would want to do what you're describing,
so there's a special case: any Java method called from within a JSNI
method that itself gets called will not be discarded. It's up to you to
decide how you want to guarantee that the JSNI method gets called in
the first place; an easy approach is to call a "init()" function from
within a module entry point.
That's the terse description. An example will hopefully make more
sense...
=== BEGIN
package foo;
public class MyEntryPoint implements EntryPoint {
public void onModuleLoad() {
initJavaScriptApi();
}
private native void initJavaScriptApi() /*-{
// define a static JS function with a friendly name
$wnd.sayHello = function () { @foo.MyEntryPoint::sayHello()() };
}-*/;
// This method will not be discarded since
// (1) initJavaScriptApi() calls this method from JSNI
// (2) initJavaScriptApi() is definitely called
public static void sayHello() {
Window.alert("hello");
}
}
=== END
Now in your host html you can write JavaScript using the "pretty"
identifiers you assigned in the initJavaScriptApi() method above, like
this:
// regular-old JavaScript
function someJavaScriptFunction() {
sayHello();
}
This technique lets you create JavaScript APIs that call into your
compiled Java code while your Java code is still completely optimized
and obfuscated -- the best of both worlds.
-- Bruce
P.S. I didn't actually run the code snippet above, so there could be
minor errors. It's really meant to show the pattern rather than to be
copied/pasted.
> This technique lets you create JavaScript APIs that call into your
> compiled Java code while your Java code is still completely optimized
> and obfuscated -- the best of both worlds.
Cool! I didn't think of that. It's really a nice way to do this sort
of things. Thanks for pointing us to it!
Regards,
Roman
Using JSNI assign a method ( in the same way one reads a java static
field) to a javascript variable and stick it somewhere for your regular
javascript to find and execute.
Because its static there is no issues regarding this etc.
I have done something similar to hte above and it seems to take care of
the unreferenced method getting excluded from the generated js.
HTH
mP
That's exactly what we ended up doing. I think we actually did that on
the same day I made the post. I probably should have checked back here
sooner and indicated that we had a workable solution.
Again, thanks for the reply. I'm extremely impressed by the
responsiveness of your team of developers and support people. Keep up
the good work!
===BEGIN
package foo;
public class MyEntryPoint implements EntryPoint {
public void onModuleLoad() {
initJavaScriptApi();
}
private native void initJavaScriptApi() /*-{
// define a static JS function with a friendly name
$wnd.sayHello = function () {
@foo.MyEntryPoint::sayHello(Ljava/lang/String;)(s) };
}-*/;
// This method will not be discarded since
// (1) initJavaScriptApi() calls this method from JSNI
// (2) initJavaScriptApi() is definitely called
public static void sayHello(String s) {
Window.alert(msg);
}
}
===END
// regular-old JavaScript
function someJavaScriptFunction() {
sayHello("hello");
}
But could not get it to work. Could someone clarify the parameter
specification??
Thanks in advance.