- Loading...
...
| Code Block | ||
|---|---|---|
| ||
var JFunction = Java.type('java.util.function.Function')
var obj = new JFunction() {
apply: function(x) { print(x*x) }
}
// every lambda object is a 'function'
print(typeof obj); // prints "function"
// 'calls' lambda as though it is a function
obj(91); |
Sometimes you may want to create a script friendly proxy object adapting another object. You can implement such a proxy in Java code or JavaScript code.
Nashorn exposes script objects as an object of jdk.nashorn.api.scripting.JSObject to java code. It is also possible to provide your own jdk.nashorn.api.scripting.JSObject implementation and nashorn will treat such objects specially (by calling magic methods for property getter, setter, delete etc.)
| Code Block | ||
|---|---|---|
| ||
import jdk.nashorn.api.scripting.AbstractJSObject;
import java.nio.DoubleBuffer;
/**
* Simple class demonstrating pluggable script object
* implementation. By implementing jdk.nashorn.api.scripting.JSObject
* (or extending AbstractJSObject which implements it), you
* can supply a friendly script object. Nashorn will call
* 'magic' methods on such a class on 'obj.foo, obj.foo = 33,
* obj.bar()' etc. from script.
*
* In this example, Java nio DoubleBuffer object is wrapped
* as a friendly script object that provides indexed acces
* to buffer content and also support array-like "length"
* readonly property to retrieve buffer's capacity. This class
* also demonstrates a function valued property called "buf".
* On 'buf' method, we return the underlying nio buffer object
* that is being wrapped.
*/
public class BufferArray extends AbstractJSObject {
// underlying nio buffer
private final DoubleBuffer buf;
public BufferArray(int size) {
buf = DoubleBuffer.allocate(size);
}
public BufferArray(DoubleBuffer buf) {
this.buf = buf;
}
// called to check if indexed property exists
@Override
public boolean hasSlot(int index) {
return index > 0 && index < buf.capacity();
}
// get the value from that index
@Override
public Object getSlot(int index) {
return buf.get(index);
}
// set the value at that index
@Override
public void setSlot(int index, Object value) {
buf.put(index, ((Number)value).doubleValue());
}
// do you have a property of that given name?
@Override
public boolean hasMember(String name) {
return "length".equals(name) || "buf".equals(name);
}
// get the value of that named property
@Override
public Object getMember(String name) {
switch (name) {
case "length":
return buf.capacity();
case "buf":
// return a 'function' value for this property
return new AbstractJSObject() {
@Override
public Object call(Object thiz, Object... args) {
return BufferArray.this.buf;
}
// yes, I'm a function !
@Override
public boolean isFunction() {
return true;
}
};
}
return null;
}
} |
JS example using the above JSObject implementation is as follows:
| Code Block | ||
|---|---|---|
| ||
// Usage: jjs -scripting -cp . jsobject.js
// This sample demonstrats how to expose a
// script friendly object from your java code
// by implementing jdk.nashorn.api.scripting.JSObject
// compile the java program
`javac BufferArray.java`
// print error, if any and exit
if ($ERR != '') {
print($ERR)
exit($EXIT)
}
// create BufferArray
var BufferArray = Java.type("BufferArray")
var bb = new BufferArray(10)
// 'magic' methods called to retrieve set/get
// properties on BufferArray instance
var len = bb.length
print("bb.length = " + len)
for (var i = 0; i < len; i++) {
bb[i] = i*i
}
for (var i = 0; i < len; i++) {
print(bb[i])
}
// get underlying buffer by calling a method
// on BufferArray magic object
// 'buf' is a function member
print(typeof bb.buf)
var buf = bb.buf()
// use retrieved underlying nio buffer
var cap = buf.capacity()
print("buf.capacity() = " + cap)
for (var i = 0; i < cap; i++) {
print(buf.get(i))
} |
| Anchor | ||||
|---|---|---|---|---|
|
JSAdapter
...
JSAdapter supports java.lang.reflect.Proxy-like proxy mechanism for script objects. i.e., it allows script proxy
objects be implemented in script itself.
| Code Block | ||
|---|---|---|
| ||
// A JSAdapter object with proxy-like special hooks
var obj = new JSAdapter() {
__get__: function(name) {
print("getter called for '" + name + "'"); return name;
},
__put__: function(name, value) {
print("setter called for '" + name + "' with " + value);
},
__call__: function(name, arg1, arg2) {
print("method '" + name + "' called with " + arg1 + ", " + arg2);
},
__new__: function(arg1, arg2) {
print("new with " + arg1 + ", " + arg2);
},
__getIds__: function() {
print("__getIds__ called");
return [ "foo", "bar" ];
},
__getValues__: function() {
print("__getValues__ called");
return [ "fooval", "barval" ];
},
__has__: function(name) {ECMAscript typed arrays
print("__has__ called with '" + name + "'");
return name == "js";
},
__delete__: function(name) {
print("__delete__ called with '" + name + "'");
return true;
}
};
// calls __get__
print(obj.foo);
// calls __put__
obj.foo = 33;
// calls __call__
obj.func("hello", "world");
// calls __new__
new obj("hey!", "it works!");
// calls __getIds__ to get array of properties
for (i in obj) {
print(i);
}
// calls __getValues__ to get array of property values
for each (i in obj) {
print(i);
}
|
...