I'm using this library to run some javascript on android - https://github.com/LiquidPlayer/LiquidCore/wiki/LiquidCore-as-a-Native-Javascript-Engine
I've got some objects that I am exposing to javascript no problem, but I would like to bind some functions to that class as true getter/setter properties.
The syntax for doing this in javascript is:
Object.defineProperty(viewWrapper, 'width', {
get: function () {
return viewWrapper.view.width();
}
});
I've found this class: http://ericwlange.github.io/org/liquidplayer/webkit/javascriptcore/JSObjectPropertiesMap.html
I've seen this reference in apples docs: https://developer.apple.com/documentation/javascriptcore/jsvalue/1451542-defineproperty
The reason for me doing this, is to shadow existing objects perfectly, so I have to be able to replicate the getter/setter style. I could do the work at the javascript layer, but I'm trying to write the least code possible, and expose fully formed objects from the java side.
I tried this on this page, but it just ended up binding the functions themselves.
There is another way to do it that is not particularly well documented, but is far more elegant. You can use the @jsexport
attribute on a JSObject
.
private class Foo extends JSObject {
Foo(JSContext ctx) { super(ctx); }
@jsexport(type = Integer.class)
Property<Integer> x;
@jsexport(type = String.class)
Property<String> y;
@jsexport(attributes = JSPropertyAttributeReadOnly)
Property<String> read_only;
@SuppressWarnings("unused")
@jsexport(attributes = JSPropertyAttributeReadOnly | JSPropertyAttributeDontDelete)
int incr(int x) {
return x+1;
}
}
Then you can use the getter/setter methods in both Java and Javascript:
Foo foo = new Foo(ctx);
ctx.property("foo", foo);
ctx.evaluateScript("foo.x = 5; foo.y = 'test';");
assertEquals((Integer)5, foo.x.get());
assertEquals("test", foo.y.get());
foo.x.set(6);
foo.y.set("test2");
assertEquals(6, foo.property("x").toNumber().intValue());
assertEquals("test2", foo.property("y").toString());
assertEquals(6, ctx.evaluateScript("foo.x").toNumber().intValue());
assertEquals("test2",
ctx.evaluateScript("foo.y").toString());
ctx.evaluateScript("foo.x = 11");
assertEquals((Integer)11, foo.x.get());
assertEquals(21,
ctx.evaluateScript("foo.incr(20)").toNumber().intValue());
foo.read_only.set("Ok!");
assertEquals("Ok!", foo.read_only.get());
foo.read_only.set("Not Ok!");
assertEquals("Ok!", foo.read_only.get());
ctx.evaluateScript("foo.read_only = 'boo';");
assertEquals("Ok!", foo.read_only.get());