I have a Scriptable bean as shown below
package test.rhino;
import java.util.HashMap;
import org.mozilla.javascript.Scriptable;
public class SomeBean implements Scriptable {
/**
* The current values for this object.
*/
private HashMap<String, Object> values = new HashMap<>();
/**
*
*/
public SomeBean() {
System.out.println("SomeBean();");
}
/*
* @see org.mozilla.javascript.Scriptable#getClassName()
*/
@Override
public String getClassName() {
return "SomeBean";
}
/*
* @see org.mozilla.javascript.Scriptable#get(java.lang.String,
* org.mozilla.javascript.Scriptable)
*/
@Override
public Object get(String name, Scriptable start) {
System.out.println("Get is called.");
System.out.println("Called for this" + name + " and returned :" + values.get(name));
return values.get(name);
}
/*
* @see org.mozilla.javascript.Scriptable#put(java.lang.String,
* org.mozilla.javascript.Scriptable, java.lang.Object)
*/
@Override
public void put(String name, Scriptable start, Object value) {
System.out.println("Put is called. Input name: " + name + "\n Input values: " + value);
values.put(name, value);
}
@Override
public Object get(int index, Scriptable start) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean has(String name, Scriptable start) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean has(int index, Scriptable start) {
// TODO Auto-generated method stub
return false;
}
@Override
public void put(int index, Scriptable start, Object value) {
// TODO Auto-generated method stub
}
@Override
public void delete(String name) {
// TODO Auto-generated method stub
}
@Override
public void delete(int index) {
// TODO Auto-generated method stub
}
@Override
public Scriptable getPrototype() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setPrototype(Scriptable prototype) {
// TODO Auto-generated method stub
}
@Override
public Scriptable getParentScope() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setParentScope(Scriptable parent) {
// TODO Auto-generated method stub
}
@Override
public Object[] getIds() {
// TODO Auto-generated method stub
return null;
}
@Override
public Object getDefaultValue(Class<?> hint) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean hasInstance(Scriptable instance) {
// TODO Auto-generated method stub
return false;
}
}
In Rhino, using javascript i can access the keys in underlying HashMap as the bean's properties.
var bean = new SomeBean();"
+ "bean.nomen = 'John Doe';\n"
+ "bean.nomen2 = bean.nomen + ' is cool';
The output shows the get and put being called the key and value being added and accessed from the HashMap 'values' . This way i can also add additional functionality to get() and put() method definition.
While porting this bean to Nashorn, i could not find a way to have the same functionality. Nashorn does expose the HashMap in Javascript and allows us to add entries but for me, this behavior should be accessible from the bean instance through a common setter or getter so that i can do more stuff while values are added and retrieved from the HashMap.
So it should work like below :-
Assume bean = new SomeBean();
bean.name = 'John Doe' // Adds name and John Doe to the HashMap
print(bean.name) // Retrieves John Doe.
Is there a way to accomplish this in Nashorn?. I am aware that public class variables are available to my bean instance but that doesn't give me the same functionality as shown above. I do not want to access the HashMap directly either.
Thanks.
After a lot of digging, I was able to resolve this by extending my bean from 'AbstractJSObject' class. This class had proxy get, set and has methods that will be invoked when we try to access/change the object properties with a dot operator.
The changed class looks like below.
package test.nashorn;
import java.util.HashMap;
import jdk.nashorn.api.scripting.AbstractJSObject;
public class NSomeOtherBean extends AbstractJSObject {
/**
* The current values for this object.
*/
private HashMap<String, Object> values = new HashMap<>();
public NSomeOtherBean() {
System.out.println("Constructor called.");
}
// do you have a property of that given name?
@Override
public boolean hasMember(String name) {
return has(name);
}
// get the value of that named property
@Override
public Object getMember(String name) {
return get(name);
}
// get the value of that named property
@Override
public void setMember(String name,Object value) {
put(name,value);
}
public Object get(String name) {
System.out.println("JAVA Get is called.");
// System.out.println("Called for this"+name+" and returned
// :"+values.get(name));
return values.get(name);
}
public void put(String name, Object value) {
System.out.println("JAVA Put is called. Input name: " + name + "\n Input values: " + value);
values.put(name, value);
}
public boolean has(String name) {
System.out.println("JAVA Has is called. Input name: " + name);
return values.containsKey(name);
}
}