Clone all JavaScript ScriptEngine

I need to somehow deeply clone the entire set of bindings of my ScriptEngine object.

What i tried

  • I already tried the Cloner library to clone the entire Bindings framework. It would be great if this worked because it would provide an exact copy, including private variables. But this leads to damage to the jvm heap (jvm just crashes with exit code -1073740940). Sometimes this does not fail, but strange things happen, for example, System.out.println() stops working as it should ...

  • I also studied cloning objects using js code inside ScriptEngine so that I can get them as NativeObjects and manage them on some Java maps. But all the cloning methods that I have found have flaws. I want to get an accurate snapshot of objects. For example, if each of the two objects a and b contains fields (say, a.fa and b.fb) that reference the same object c, when cloning using jQuery.extend() (for example) fields a.fa and b.fb cloned a and b will refer to different clones of c, and not refer to the same clone. And many other problems.

  • I also tried to clone the entire ScriptEngine using Cloner (not just bindings), and I also tried to use the Rhino js engine and clone the entire area (instead of the ScriptEngine wrapper). But the problem of a bunch of corruption persists.

Why do I need it

I need this because I should be able to restore the values ​​of all ScriptEngine bindings to some previous point. I need to take accurate snapshots of the bindings.

The application is part of my doctoral research project, which consists of running machine states with nodes (implemented in java) with js code attached. The js code is entered by the end user and it is displayed at runtime. When the final state cannot be reached along the path, the algorithm takes steps back, trying to find alternative paths. At each step back, it should undo any changes that might have occurred in the js engine bindings.


All global variable names are known before js eval-ing and are objects (the user enters the code for the nodes and then organizes (inside java) into js objects with specific name patterns). But their content can be anything, because it is controlled by user code js.

So, I think that my only solution now is to clone the js object using js code.

+6
source share
2 answers

In addition to "edge cases", jQuery.extend can be used as you mentioned. a b , and their clones will refer to the same object c .

 var c = { f:'see' }; var a = { fa: c }; var b = { fb: c }; var cloneA = $.extend({}, a); var cloneB = $.extend({}, b); console.log(a.fa === b.fb, cloneA.fa === cloneB.fb, a.fa === cloneB.fb); // true true true 

But it looks like you want to clone all objects (including c ) by tracking the relationships of the objects. For this, it is best to use object relationship tables.

I see this a lot with nested javascript and JSON objects, because people tend to forget that JSON is a purely text format. There are no real javascript objects in the JSON file except one line of text instanceof String . There is no beans or pickles or any conservatively heavy products in javascript.

In the table of object relations, each "table" is just an array of "flat" objects with only primitively evaluated properties and pointers (not links) to other objects in the table (or in another table). The pointer can only be the index of the target.

Thus, the JSON version of the above relation to the object may look something like this:

 { "table-1":[ { "a": { "fa":["table-2",0] } }, { "b": { "fb":["table-2",0] } } ], "table-2":[ { "c": { "name":"see" } }, { "d": { "name":"dee" } }, { "e": { "name":"eh.."} } ] } 

And the parser might look like

 var tables = JSON.parse(jsonString); for(var key in tables){ var table = tables[key]; for(var i = 0; i < table.length; i++){ var name = Object.keys(table[i]) var obj = table[i][name]; for(var key2 in obj){ if(obj[key2] instanceof Array && obj[key2][0] in tables){ var refTable = obj[key2][0]; var refID = obj[key2][1]; var refObj = tables[refTable][refID]; var refKey = Object.keys(refObj)[0]; obj[key2] = refObj[refKey]; } } this[name] = obj; } } console.log(a.fa === b.fb, b.fb === c); // true true 

I understand that comparing the relationship to an object has problems, but photographing the script engine sounds a little crazy. Especially since your intention is to be able to remember each previous step, because then you need a new snapshot for each step ... which will very quickly take the shit a ton of disk space .. if you just track the snapshot the difference between each step like a git repository. It sounds like a terrible job to implement a seemingly simple β€œundo” method.

Damn it ... think about it, why not just store every step in the story file? Then, if you need to step back, just crop the history file in the previous step and run each step again in the new environment.

Not sure how practical it would be (in terms of performance) using java. Nodejs (as it exists today) is faster than any java script engine will ever be. In fact, I'm just going to call it ECMAscript from now on. Sorry to pounce, its just

Java is slow, but you already know.
Because it easily shows that as fast as it happens.

+3
source

May I suggest a different approach.

  • Do not try to clone ScriptEngine. It does not implement Serializable / Externalizable, and the API does not support cloning. Attempts to force a clone will be workarounds that may arise in some future versions of Java.

  • Serialize JSON bindings using cycle.js . It will encode object references in the form {$ref: PATH} . When you do the deserialization, it will restore the links.

    As far as I can tell, the .js loop does not serialize functions, but you can add it to serialize functions yourself using Function.toString () (see below and Example )

Alternatively, if using the library is not an option, simply implement your serialization to suit your needs:

 var jsonString = JSON.stringify(obj, function(key, val) { if (typeof(value) === 'function') return val.toString(); // or do something else with value like detect a reference return val }) 
+2
source

Source: https://habr.com/ru/post/918541/


All Articles