I want to put global property named "entities" in JS scope. Entity
is basically Java class describing Person.
public class EntityJS extends ScriptableObject {
private String firstName;
private String lastName;
private Double salary;
private String email;
@Override
public String getClassName() {
return "Entity";
}
public EntityJS() {
}
public EntityJS(String firstName, String lastName, Double salary, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.email = email;
}
public void jsConstructor() {
this.firstName = "";
this.lastName = "";
this.salary = 0.;
this.email = "";
}
public void jsSet_salary(Double value) {
this.salary = value;
}
public Double jsGet_salary() {
return this.salary;
}
public void jsSet_firstName(String value) {
this.firstName = value;
}
//the rest of getters & setters
}
Entity
class is almost the same class like EntityJS
, except it extends only java Object
.
I want to allow javascript user modify global variable "entities". After executing user's script, I want to retrieve this object back to Java (and perform some operations later on).
I've commented interesting lines with results and expected returned values. Here is my code of trying to execute user's code:
public String execute(String code, ObservableList<Entity> entities) {
Context context = Context.enter();
try {
Scriptable scope = context.initStandardObjects();
ScriptableObject.defineClass(scope, EntityJS.class, true, true);
EntityJS[] objects = new EntityJS[entities.size()];
for(int i = 0; i < entities.size(); ++i){
objects[i] = new EntityJS(entities.get(i).getFirstName(), entities.get(i).getLastName(), entities.get(i).getSalary(), entities.get(i).getEmail());
}
ScriptableObject.putProperty(scope, "e1", Context.javaToJS(objects, scope));
// typing "e1" (which is equal to "code" value) returns "[Lentity.EntityJS;@7959b389"
Object[] array = entities.toArray();
ScriptableObject.putProperty(scope, "e2", array);
// same for e1
Object wrappedOut = Context.javaToJS(entities, scope);
ScriptableObject.putProperty(scope, "e3", wrappedOut);
//this works quite nice, but it doesn't behave like JS object
//it returns, good-looking array:
//[Entity{firstName='Alwafaa', lastName='Abacki', salary=1000.0, email='zdzisiek@adad.com'},
//Entity{firstName='chero', lastName='Cabacki', salary=2000.0, email='bfadaw@dadaad.com'}]
//Unfortunately, if I want to get e.g. salary value I have to call
//e.get(0).getSalary() which returns string :(
//if I want to add number I have to call
//Number(e.get(0).getSalary()) to get Number
ScriptableObject.putProperty(scope, "e4", Context.javaToJS(objects[0], scope));
//this results in "TypeError: Cannot find default value for object."
Object result = context.evaluateString(scope, code, "<cmd>", 1, null);
return context.toString(result);
} catch (Exception ex) {
System.out.println(ex.getMessage());
return ex.getMessage();
} finally {
Context.exit();
}
}
I want to give user "entities" JS-like array, which could be modified e.g. this way:
entities.forEach(function(entity){entity.salary += 1000;})
I'd like salary
property to be Number
, of course.
Does someone know how can I approach this?
Thanks in advance