gpt4 book ai didi

java - 无缝地将数组和列表传入和传出 Nashorn

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:25:37 25 4
gpt4 key购买 nike

我知道您可以在 Nashorn 中使用 Java 数组,并且有很多示例说明如何执行此操作。对我来说,标准方法的问题是它使 javascript 代码明确知道它的运行时环境。目前我有一个使用 Rhino 的解决方案,它可以在 Java 类型和 native javascript 类型之间无缝转换。

对于 Rhino,我通过实现 org.mozilla.javascript.ContextFactoryorg.mozilla.javascript.WrapFActory 并将 WrapFactory 设置为调用 makeContext 时的 Context。此 WrapFactory 实现负责 Java 数组和列表与 native javascript 数组和列表之间的转换。值得一提的是,我必须从 JDK 获取 Rhino 源代码才能使这种方法起作用。

我需要为 Nashorn 找到类似的解决方案。这是我正在尝试完成的示例。

public static void main(String args[]) {
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine();
try {
engine.eval("function print_array(arr) { print(arr); }");
engine.eval("function print_native() { print_array([1, 2, 3, 4]); }");
Invocable invocable = (Invocable) engine;
invocable.invokeFunction("print_array", new int[]{1, 2, 3, 4});
invocable.invokeFunction("print_array", Arrays.asList(1, 2, 3, 4));
invocable.invokeFunction("print_native");
} catch (ScriptException | NoSuchMethodException e) {
e.printStackTrace();
}
}

这段代码的输出是

[I@169e6180

[1, 2, 3, 4]

1,2,3,4

我正在寻找一种实现 ScriptObjectMirror 的方法,假设它是正确的,这将使这三个 invokeFunction 调用的输出相同。

我已经尝试在 ScriptUtils 上使用 wrap 函数,但结果仍然是错误的

更新

我试图创建一个 Invocable 类型的动态代理,并在 InvocationHandler 中进行转换。要使用 Nashorn 创建 NativeArray,您似乎应该使用 jdk.nashorn.internal.objects.Global.allocate,但这总是会引发异常。

Global.allocate(new int[] {1, 2, 3, 4})

加注

Exception in thread "main" java.lang.NullPointerException
at jdk.nashorn.internal.objects.Global.instance(Global.java:491)
at jdk.nashorn.internal.objects.NativeArray.<init>(NativeArray.java:141)
at jdk.nashorn.internal.objects.Global.allocate(Global.java:1584)

最佳答案

我认为您必须走艰难的道路才能实现 AbstractJSObject。我认为很多像 getMember 这样的函数都可以通过 Refelction 来完成。但是如果有人认为它是一个 JS 数组并尝试扩展原型(prototype),你会怎么做?你也想处理这个吗?在那种情况下,我将实现一个 JS 数组作为列表中的属性,如包装类,并将所有设置/添加委托(delegate)给更新 JS 对象的 JS 函数。

解决方案一:

public static void main(String args[]) {
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine();

try {
engine.eval("function print_array(arr) { print(arr); for(var i=0; i<arr.length; i++) {print(arr[i]);}}");
engine.eval("function print_native() { print_array([1, 2, 3, 4]); }");
engine.eval("function get_native() { return [1, 2, 3, 4]; }");
Invocable invocable = (Invocable) engine;
invocable.invokeFunction("print_array", new int[]{1, 2, 3, 4});
invocable.invokeFunction("print_array", Arrays.asList(1, 2, 3, 4));
invocable.invokeFunction("print_array", new Foo());
invocable.invokeFunction("print_native");

ScriptObjectMirror a = (ScriptObjectMirror) invocable.invokeFunction("get_native");
System.out.println(invocable.invokeFunction("get_native"));

} catch (Exception e) {
e.printStackTrace();
}
}

static class Foo extends AbstractJSObject {
Map<Integer, Object> arrayValues = new HashMap<>();

public Foo() {
arrayValues.put(0, 1);
arrayValues.put(1, 2);
arrayValues.put(2, 3);
}
@Override
public Object call(Object thiz, Object... args) {
System.out.println("call");
return super.call(thiz, args);
}

@Override
public Object newObject(Object... args) {
System.out.println("new Object");
return super.newObject(args);
}

@Override
public Object eval(String s) {
System.out.println("eval");
return super.eval(s);
}

@Override
public Object getMember(String name) {
System.out.println("getMember " + name);
return name.equals("length") ? arrayValues.size() : arrayValues.get(Integer.valueOf(name));
}

@Override
public Object getSlot(int index) {
//System.out.println("getSlot");
return arrayValues.get(index);
}

@Override
public boolean hasMember(String name) {
System.out.println("hasMember");
return super.hasMember(name);
}

@Override
public boolean hasSlot(int slot) {
System.out.println("hasSlot");
return super.hasSlot(slot);
}

@Override
public void removeMember(String name) {
System.out.println("removeMember");
super.removeMember(name);
}

@Override
public void setMember(String name, Object value) {
System.out.println("setMember");
super.setMember(name, value);
}

@Override
public void setSlot(int index, Object value) {
System.out.println("setSlot");
super.setSlot(index, value);
}

@Override
public Set<String> keySet() {
System.out.println("keySet");
return arrayValues.keySet().stream().map(k -> "" + k).collect(Collectors.toSet());
}

@Override
public Collection<Object> values() {
System.out.println("values");
return arrayValues.values();
}

@Override
public boolean isInstance(Object instance) {
System.out.println("isInstance");
return super.isInstance(instance);
}

@Override
public boolean isInstanceOf(Object clazz) {
System.out.println("isINstanceOf");
return super.isInstanceOf(clazz);
}

@Override
public String getClassName() {
System.out.println("getClassName");
return super.getClassName();
}

@Override
public boolean isFunction() {
return false;
}

@Override
public boolean isStrictFunction() {
return false;
}

@Override
public double toNumber() {
return super.toNumber();
}

@Override
public boolean isArray() {
return true;
}

@Override
public String toString() {
return arrayValues.values().toString();
}
}

解决方案 2 是(伪代码):

static class FooList implements List {
final ScriptObjectMirror wrapped;

public FooList(ScriptObjectMirror wrapped) {
this.wrapped = wrapped;
}

@Override
public int size() {
return engine.eval("get length of wrapped JS object");
}

... and so on ...
}

关于java - 无缝地将数组和列表传入和传出 Nashorn,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30571711/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com