Motivated by this latest burst of activity, I got jsni support working
again on top of the latest version of scalagwt. Right now it only
supports calling into native javascript from scala, not back out
again, but that's already enough to do some pretty cool things,
including implementing JavaScriptObjects using scala classes. I've
added an example to the sample project to test/show off some of what
is possible: https://github.com/maffoo/scalagwt-sample/blob/master/src/com/google/gwt/sample/jsni/client/HelloJsni.scala
To specify the method bodies, you need a function called 'nativeCode'
that takes a single string parameter and returns Nothing (ie raises an
exception). We discussed adding this method to the scala.util
package, but for now the gwt compiler will accept any method called
nativeCode, regardless of the package, so you can define nativeCode in
your project as I've done in the sample. Also, note that you have to
annotate the methods as @native so that the devMode system, which
looks at the compiled class files, will see that they are native and
look up the jsni method bodies, rather than trying to execute them.
(One issue with jribble right now is that even though it has a Native
flag for method declarations, the flag is not being set correctly. It
would be nice to fix this, but I didn't make much headway on that the
last time I looked at it.)
My repo with the jsni updates is here:
https://github.com/maffoo/scalagwt-gwt
Also, I've generated a pull request to get this in to the main branch:
https://github.com/scalagwt/scalagwt-gwt/pull/39
Please let me know what you think.
-Matthew
PS- One caveat regarding the use of JavaScriptObjects with scala. A
common pattern with gwt in java is to define a Jso class with static
native constructor methods, e.g.:
class Point extends JavaScriptObject {
public static native Point create(int x, int y) /*-{ return [x, y]; }-*/;
protected Point() {}
public native int getX() /*-{ return this[0]; }-*/;
public native int getY() /*-{ return this[1]; }-*/;
}
The roughly equivalent thing we'd like to do in scala would be to have
a Point class with a companion object to hold the statics:
class Point protected() extends JavaScriptObject {
@native def x: Int = nativeCode(" return this[0]; ")
@native def y: Int = nativeCode(" return this[1]; ")
}
object Point {
@native def create(x: Int, y: Int): Point = nativeCode(" return [x, y]; ")
}
Unfortunately, this does not work, because having a companion object
is not exactly the same as having static methods on a class. In
hosted mode the call to Point.create fails with an error saying the
MODULE$ field is not found. If you compile down to javascript it
turns out everything works fine again, but not having hosted mode is
sort of a deal breaker. If anyone with more knowledge of scala
internals and jribble has any ideas about how to fix this, that would
be great, but for now, just put your jso constructor methods on some
other object which is not a companion and everything works fine.
Hi All-
Motivated by this latest burst of activity, I got jsni support working
again on top of the latest version of scalagwt. Right now it only
supports calling into native javascript from scala, not back out
again, but that's already enough to do some pretty cool things,
including implementing JavaScriptObjects using scala classes. I've
added an example to the sample project to test/show off some of what
is possible: https://github.com/maffoo/scalagwt-sample/blob/master/src/com/google/gwt/sample/jsni/client/HelloJsni.scala
To specify the method bodies, you need a function called 'nativeCode'
that takes a single string parameter and returns Nothing (ie raises an
exception). We discussed adding this method to the scala.util
package, but for now the gwt compiler will accept any method called
nativeCode, regardless of the package, so you can define nativeCode in
your project as I've done in the sample.
Also, note that you have to
annotate the methods as @native so that the devMode system, which
looks at the compiled class files, will see that they are native and
look up the jsni method bodies, rather than trying to execute them.
(One issue with jribble right now is that even though it has a Native
flag for method declarations, the flag is not being set correctly. It
would be nice to fix this, but I didn't make much headway on that the
last time I looked at it.)
My repo with the jsni updates is here:
https://github.com/maffoo/scalagwt-gwt
Also, I've generated a pull request to get this in to the main branch:
https://github.com/scalagwt/scalagwt-gwt/pull/39
Please let me know what you think.
Your fix works for me, thanks for the quick response. Given that
methods have to be marked @native to work with devmode anyway, I
propose to remove the isNative() code which looks at the jribble, and
instead just go by the @native flag. Then, inside jsniGetNativeCode
I'll do all the checks to ensure that the jribble is properly formed
for a native method call. What do you think?
>
>> My repo with the jsni updates is here:
>> https://github.com/maffoo/scalagwt-gwt
>>
>> Also, I've generated a pull request to get this in to the main branch:
>> https://github.com/scalagwt/scalagwt-gwt/pull/39
>>
>> Please let me know what you think.
>
>
> Your change looks very promising already. Two things I'd like to get added:
>
> comments explaining all the logic behind detecting and extracting javascript
> code
> tests, they are easy to write now
>
> Once this is done and you verify that scala compiler fix I posted works for
> you let's have another iteration (new pull request with some commits
> squashed). I'll have a more detailed look into your change then.
>
> I want to cut next release around next Friday (or Monday just before Scala
> Days). Let me know if you can make it for the release.
>
I think it should be no problem to have this ready by Friday. I
update the pull request with some comments and I'll try to get some
tests written today.
I'm not exactly sure what's going wrong. The example I gave above
compiles to javascript and works just fine, but in hosted mode a call
to Point.create(x, y) will fail with an error
java.lang.NoSuchFieldError: MODULE$
At first I thought the issue was with how JavaScriptObject objects are
represented at runtime in devmode, but the MODULE$ field lives on the
Point$ class, not the Point class which is the JavaScriptObject, so
I'm still confused by this error. If you have any insight, that would
be great.
-Matthew
Cheers,
Matthew