Marcus,
After a bit of thinking about it I've worked out a way of linking jep
variables to objects it does involve quite a few classes
VariableBinding: an interface which defines how a variable can be
bound to an object
BoundVariable: a variable bound to an object
BoundVariableFactory: a factory for creating bound variables
FieldVariableBinding: A particular VariableBinding which links
variables to a particular field on an object
VariableBindingMapper: An interface defining what to do with new
variable names
ChainedObjectVariableBindingMapper: Translates a variable names of the
form z.a.b into reference to a field of a field of an object.
BoundVariableTest: Test class and example
Richard
************ VariableBinding **************************
package com.singularsys.jep.misc.boundvariable;
import java.io.Serializable;
/**
* Bound variables will call these methods to interact with objects
outside of Jep.
*
* @author Richard Morris
* @since Jep 3.5
*/
public interface VariableBinding extends Serializable {
/**
* Gets the value of a variable.
* @return the value
* @throws Exception if there is a problem getting the variable value
*/
Object getValue() throws Exception;
/**
* Sets the value of a variable.
* @param value
* @throws Exception if there is a problem setting the variable value
*/
void setValue(Object value) throws Exception;
}
*********** BoundVariable ******************
package com.singularsys.jep.misc.boundvariable;
import com.singularsys.jep.Variable;
/**
* A variable bound to an object outside of Jep.
* @author Richard Morris
* @since Jep 3.5
*/
public class BoundVariable extends Variable {
private static final long serialVersionUID = 350L;
protected VariableBinding vb;
/**
* Create a BoundVariable
* @param name name of the variable
* @param vb binding for the variable
*/
public BoundVariable(String name,VariableBinding vb) {
super(name);
this.vb = vb;
}
/**
* Gets the value of the variable.
* @return the value of the object. Returns null if there is problem
accessing the variable.
*/
@Override
public Object getValue() {
try {
return vb.getValue();
} catch (Exception e) {
return null;
}
}
/**
* Sets the value of the variable.
* @return false if there is a problem accessing the variable
*/
@Override
protected boolean setValueRaw(Object object) {
try {
vb.setValue(object);
this.setValidValue(true);
return true;
} catch(Exception e) {
return false;
}
}
}
************** BoundVariableFactory ******************
package com.singularsys.jep.misc.boundvariable;
import com.singularsys.jep.Variable;
import com.singularsys.jep.VariableFactory;
/**
* <p>A variable factory for creating bound variables.</p>
* <p>
* If a variable is called with an {@link VariableBinding} as its
value then
* a {@link BoundVariable} will be created.
* </p>
* @author Richard Morris
* @since Jep 3.5
*/
public class BoundVariableFactory extends VariableFactory {
private static final long serialVersionUID = 350L;
protected VariableBindingMapper vom;
/**
* Create the factory with no VariableMapping.
* When a new variable is requested
*/
public BoundVariableFactory() {
}
/**
* Create the factory with a specific VariableMapping for creation of
new variables.
* @param vom
*/
public BoundVariableFactory(VariableBindingMapper vom) {
super();
this.vom = vom;
}
@Override
public Variable createVariable(String name) {
if(vom!=null) {
VariableBinding obj = vom.mapVariableName(name);
if(obj!=null)
return createVariable(name,obj);
}
return super.createVariable(name);
}
@Override
public Variable createVariable(String name, Object value) {
if(value instanceof VariableBinding)
return createVariable(name,(VariableBinding) value);
return super.createVariable(name, value);
}
/**
* Creates a variable with the given VariableBinding
* @param name name of the variable
* @param vb binding object
* @return a new BoundVariable
*/
public Variable createVariable(String name,VariableBinding vb) {
Variable var = new BoundVariable(name,vb);
return var;
}
/**
* Gets the VariableMapping for the creation of new variables.
*
* @return the mapping used or null if none set.
*/
public VariableBindingMapper getVariableMapping() {
return vom;
}
/**
* Sets the VariableMapping for the creation of new variables.
* @param vm the mapping
*/
public void setVariableMapping(VariableBindingMapper vm) {
this.vom = vm;
}
}
****************FieldVariableBinding ***************
package com.singularsys.jep.misc.boundvariable;
import java.lang.reflect.Field;
/**
* A {@link VariableBinding} which binds variables to a particular
field of an object.
*
* @author Richard Morris
* @since Jep 3.5
*/
public class FieldVariableBinding implements VariableBinding {
private static final long serialVersionUID = 350L;
protected Object obj;
protected String fieldName;
protected Field field;
/**
* Create the binding object with the name of a field.
* @param obj the object
* @param fieldName the name of the field
* @throws SecurityException
* @throws NoSuchFieldException
*/
public FieldVariableBinding(Object obj, String fieldName) throws
SecurityException, NoSuchFieldException {
super();
this.obj = obj;
this.fieldName = fieldName;
Class<? extends Object> class1 = obj.getClass();
field = class1.getField(fieldName);
}
/**
* Create the binding object with the name of a field.
* @param obj the object
* @param field a field object
*/
public FieldVariableBinding(Object obj, Field field) {
super();
this.obj = obj;
this.field = field;
this.fieldName = field.getName();
}
@Override
public Object getValue() throws IllegalArgumentException,
IllegalAccessException {
Object val = field.get(obj);
return val;
}
@Override
public void setValue(Object value) throws IllegalArgumentException,
IllegalAccessException {
field.set(obj, value);
}
}
**************VariableBindingMapper*******************
package com.singularsys.jep.misc.boundvariable;
import java.io.Serializable;
/**
* Defines a method which translates a variable name into a variable
binding.
* Used when new variable names are encountered.
* @author rich
*
*/
public interface VariableBindingMapper extends Serializable {
/**
* Creates a VariableBinding for a given variable name
* @param name name of the variable
* @return a VariableBinding or null if the name cannot be mapped.
*/
public VariableBinding mapVariableName(String name);
}
************** ChainedObjectVariableBindingMapper ********************
package com.singularsys.jep.misc.boundvariable;
import java.util.HashMap;
import java.util.Map;
/**
* Creates VariableBinding objects by translating the variable name
into a chain of object references.
* For example "foo.a.b" might be translated into a reference to field
"b" of the object at field "a" of an object.
* @author Richard Morris
* @since Jep 3.5
*/
public class ChainedObjectVariableBindingMapper implements
VariableBindingMapper {
private static final long serialVersionUID = 350L;
String sep;
Map<String,Object> baseObjects = new HashMap<String,Object>();
public ChainedObjectVariableBindingMapper(String sep) {
super();
this.sep = sep;
}
public Object put(String key, Object value) {
return baseObjects.put(key, value);
}
@Override
public VariableBinding mapVariableName(String name) {
String[] parts = name.split(sep,-1);
if (parts.length < 2) return null;
Object base = baseObjects.get(parts[0]);
int pos=1;
try {
while(pos < parts.length -1) {
base = base.getClass().getField(parts[pos]).get(base);
++pos;
}
return new FieldVariableBinding(base,parts[pos]);
} catch (Exception e) {
return null;
}
}
}
**************** BoundVariableTest *********************
package com.singularsys.jep.misc.boundvariable;
import static org.junit.Assert.*;
import org.junit.Test;
import com.singularsys.jep.Jep;
import com.singularsys.jep.Variable;
import com.singularsys.jep.parser.Node;
public class BoundVariableTest {
class MyObj {
public Double a;
public double b;
public MyObj c;
}
@Test
public void testObjectFieldAccessor() throws Exception {
Jep jep = new Jep(new BoundVariableFactory());
MyObj obj = new MyObj();
obj.a = new Double(5);
obj.b = 6;
FieldVariableBinding accA = new FieldVariableBinding(obj,"a");
FieldVariableBinding accB = new FieldVariableBinding(obj,"b");
Variable v1 = jep.addVariable("Z_a", accA);
assertEquals(new Double(5),v1.getValue());
Variable v2 = jep.addVariable("Z_b", accB);
assertEquals(new Double(6),v2.getValue());
Variable v3 = jep.addVariable("x", 3.0);
assertEquals(new Double(3),v3.getValue());
Node n = jep.parse("x+Z_a+Z_b");
Object val = jep.evaluate(n);
assertEquals(Double.valueOf(14.0),val);
Node n2 = jep.parse("Z_a=x");
Object val2 = jep.evaluate(n2);
assertEquals(Double.valueOf(3.0),val2);
assertEquals(Double.valueOf(3.0),obj.a);
Node n3 = jep.parse("Z_b=x*4");
Object val3 = jep.evaluate(n3);
assertEquals(Double.valueOf(12.0),val3);
assertEquals(12.0,obj.b,0.01);
}
@Test
public void testObjectVariableFactory() throws Exception {
ChainedObjectVariableBindingMapper uvm = new
ChainedObjectVariableBindingMapper("_");
BoundVariableFactory bvf = new BoundVariableFactory(uvm);
Jep jep = new Jep(bvf);
Variable v3 = jep.addVariable("x", 3.0);
assertEquals(new Double(3),v3.getValue());
MyObj obj = new MyObj();
obj.a = new Double(5);
obj.b = 7;
uvm.put("Z", obj);
Node n = jep.parse("x+Z_a");
Object val = jep.evaluate(n);
assertEquals(Double.valueOf(8.0),val);
MyObj obj2 = new MyObj();
obj2.a = new Double(11);
obj2.b = 13.0;
obj.c = obj2;
Node n2 = jep.parse("x+Z_c_b");
Object val2 = jep.evaluate(n2);
assertEquals(Double.valueOf(16.0),val2);
}
}
On Jan 3, 6:20 pm, Marcus Gattinger <
gattinger1...@googlemail.com>
wrote: