将 Java 脚本属性连接到 Java 对象

Connecting Javascript properties to Java object

问题

我正在尝试将 Java 对象提供给通常在网页的文档对象模型 (DOM) 上运行的脚本。在大多数情况下,这会按预期运行。但是我在处理 DOM 元素的 attributes/properties 时遇到了问题。

一个特定的 属性 利益链是 somediv.firstChild.href。我想不通的是如何动态获取 firstChild 属性 值。目前我能想到的最简单的方法是使用source.replaceAll("firstChild", "firstChild()");强制firstChild属性调用函数firstChild()。然而,这最终会打开一个新的蠕虫罐头。

问题

如何定义可以传递给 javascript 函数的对象,该函数可以通过 DOM 进行操作?

背景

从 C# 中学习

在进入 Java 之前,我学过 C#。在 C# 中,setter 和 getter 的概念非常普遍。如果这个接口方法在 Java 中可用,我的问题就会得到解决。

public string firstChild {
    get { return this.getFirstChild(); }
    set { this.setFirstChild(value); }
}

当前实施

当前通过将脚本包装在函数中调用脚本,我可以将 windowdocument Java 对象传入函数的工作区。

documentSpoofedDomElement 的特殊顶级版本(扩展它),但在功能上与下面显示的示例相同。 window 是另一个具有处理事件侦听器的最少功能的对象。

Java用于在 DOM

上运行的脚本(片段)
var somediv = document.createElement('div');
somediv.style.display = "block"
somediv.innerHTML="<a href='/mywork/server/test.html'>The Test Server Homepage</a>";
var linkvalue = somediv.firstChild.href;

此代码段存储为字符串 theOriginalSource 并在下一节中使用。

Java 评估代码 Javascript

String wrappedSource = "var scriptToInvoke = function(window, document){"
    + "\n" + theOriginalSource // from above
    + "\n};"

Object result = invocable.invokeFunction("scriptToInvoke", window, document);

此代码段包装了 javascript 代码段,以便我可以传入对象以用作 windowdocument.

Java class是恶搞 DOM 元素

public class SpoofedDomElement {
    public SpoofedDomElement firstChild;
    public String id;
    public String innerHtml;
    public String href;
    public SpoofedStyleProperties style = new SpoofedStyleProperties();
    public String tagname;
    ...
}

public class SpoofedStyleProperties {
    public String background = "transparent none repeat scroll 0% 0% auto padding-box border-box";
    public String color = null;
    public String display = "inline";
}

上面的 classes 处理了代码中不相关的部分(例如赋值 somediv.style.display = "block")。但是当处理 firstChildinnerHtml 的值时,当其中一个值发生变化时,它开始崩溃。

过去的工作

N.B. 我在所有问题中都包含了这一部分,以记录我为 Google 到达这里的未来 SO 用户所做的尝试。这可能会帮助某人通过头脑风暴找到解决方案。

尝试过的解决方案

我试图使用框架 (HtmlUnit) 来评估 Java 脚本。但我无法控制执行了哪些 Java 脚本片段。

可能的解决方案

以下是我目前正在研究寻找解决方案的问题。如果我发现任何东西,我会报告回来。

看来您正在尝试从 Java 代码实现对脚本对象的友好访问,并试图在 java 之上提供脚本友好的 API library/libraries.

第一部分[从Java访问脚本对象]

除了javax.script.Invocable接口,您还可以使用JSObject。 Nashorn 将脚本对象公开为 jdk.nashorn.api.scripting.JSObject/.ScriptObjectMirror

的实例

https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/ScriptObjectMirror.html

对于第二部分[从脚本更友好地访问 Java 个对象]

您可以使用 "JSAdapter" 在脚本本身中编写脚本友好的包装器。

文档和示例:

https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-JSAdapterconstructor

如果您更喜欢在 Java 中执行,您可以实现自己的 jdk.nashorn.api.scripting.JSObject/.AbstractJSObject.

文档和示例:

https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-jsobject

其他特定于 nashorn 的脚本扩展也可用于捕获每个对象基础上的未知 property/method 访问:

noSuchProperty 挂钩任何脚本对象:

https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-noSuchProperty

noSuchMethod 挂钩任何脚本对象:

https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-noSuchMethod

Object.bindProperties:

脚本 API 扩展可用于将一个对象的属性绑定到另一个对象 - 源对象也可以是 Java 对象。

https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-Object.bindProperties

使用 jdk9,Dynalink 可以实现更灵活的跨语言链接 API [ http://openjdk.java.net/jeps/276 ]

另请参阅:

https://blogs.oracle.com/sundararajan/entry/dynamic_linker_api_for_the

https://blogs.oracle.com/sundararajan/entry/writing_pluggable_dynalink_linker_and

https://blogs.oracle.com/sundararajan/entry/nashorn_javascript_access_to_python

Nashorn OpenJDK 存储库的 dynalink 示例 "samples/dynalink" 目录:

http://hg.openjdk.java.net/jdk9/dev/nashorn/file/4a6ee1185fc8/samples/dynalink