简体   繁体   中英

Connecting Javascript properties to Java object

The Problem

I am trying to feed a Java object into a script that would normally operate on the Document Object Model (DOM) of a web page. For the most part this functions as intended. However I have encountered a problem when dealing with attributes/properties of the DOM elements.

A particular property chain of interest is somediv.firstChild.href . What I can't figure out is how to get the firstChild property value dynamically. The simplest way I can think of at the moment is to use source.replaceAll("firstChild", "firstChild()"); to force the firstChild property to invoke the function firstChild() instead. However this will eventually open up a new can of worms.

The Question

How do I define an object that can be passed to a javascript function that can be operated on via the DOM?

Background

Learnings from C#

Before diving into Java I had learnt C#. In C# the concept of setters and getters is quite prevalent. If this interface method were available in Java my problem would be solved.

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

Current Implementation

The script is currently invoked by wrapping it in a function where I can pass in the window and document Java objects into the function's workspace.

document is a special top-level version of SpoofedDomElement (that extends it) but is functionally identical to the sample shown below. window is another object with minimal functions that handle event listeners.

Javascript (snippet) to operate on 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;

This snippet is stored as the string theOriginalSource and used in the next section.

Java code to evaluate Javascript

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

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

This snippet wraps the javascript snippet so that I can pass in objects to use as window and document .

Java classes that spoof DOM elements

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";
}

The above classes handle irrelevant parts of the code just fine (such as the assignment somediv.style.display = "block" ). But it starts to fall apart when handling the values of firstChild or innerHtml when either value is changed.

Past Work

NB I include this section in all my questions to document what I have tried for future SO users who get here by Google. This might help someone reach a solution by aiding brainstorming.

Attempted Solutions

I have attempted to use a framework ( HtmlUnit ) to evaluate the Javascript. But I couldn't control which Javascript snippets were executed.

Potential Solutions

The following are questions that I am currently researching to find a solution. If I find anything I will report back.

  • Is there a way to emulate C# getter/setter behaviour in Java?
  • Can Javascript evaluate firstChild as a function?
  • Is there a way to create a wrapper within Javascript with getter/setters that can invoke my Java class's functions?
  • Is there an Apache Commons library for Nashorn (or similar) that isn't as heavy as the complete simulation frameworks (such as Selenium )?

It appears that you're trying to implement friendly access of script objects from Java code as well as trying to provide script-friendly API on top of java library/libraries.

For the first part [ script object access from Java ]

Apart from javax.script.Invocable interface, you can use JSObject. Nashorn exposes script objects as instances of jdk.nashorn.api.scripting.JSObject/.ScriptObjectMirror

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

For the second part [ friendlier access of Java objects from scripts ]

You can write script friendly wrappers in script itself using "JSAdapter".

Doc and Example:

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

If you'd prefer to do in Java, you can implement your own jdk.nashorn.api.scripting.JSObject/.AbstractJSObject.

Doc and Example:

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

Other nashorn specific script extensions may also be used to trap unknown property/method access in per object basis:

noSuchProperty hook in any script object:

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

noSuchMethod hook in any script object:

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

Object.bindProperties:

There script API extension can be used to bind properties of one object to another - the source object could be a Java object as well.

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

With jdk9, there is more flexible inter-language linking possible with Dynalink API [ http://openjdk.java.net/jeps/276 ]

See also:

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

There are dynalink samples "samples/dynalink" directory of Nashorn OpenJDK repository:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM