Dynamic formula based on user inputs - java

I have many objects with different metrics. I am building a formula based on the user input.
class Object{
double metrics1;
double metrics2;
.. double metricsN; //number of metrics is knowned
}
Users can input
formula=metrics1
or
formula=(metrics1+metrics2)/metrics3
I already have a parser to parse the formula, but I do not know how to store this expression for further calculation.
I want to avoid parsing the formula again and again for every single object (I can have up to a few hundred thousands).

Use ScriptEngine and reflection like this.
static class Evaluator {
ScriptEngine engine = new ScriptEngineManager()
.getEngineByExtension("js");
void formula(String formula) {
try {
engine.eval("function foo() { return " + formula + "; }");
} catch (ScriptException e) {
e.printStackTrace();
}
}
Object eval(Object values)
throws ScriptException,
IllegalArgumentException,
IllegalAccessException {
for (Field f : values.getClass().getFields())
engine.put(f.getName(), f.get(values));
return engine.eval("foo()");
}
}
public static class Object1 {
public double metrics1;
public double metrics2;
Object1(double metrics1, double metrics2) {
this.metrics1 = metrics1;
this.metrics2 = metrics2;
}
}
public static void main(String[] args)
throws ScriptException,
IllegalArgumentException,
IllegalAccessException {
Evaluator e = new Evaluator();
e.formula("metrics1 + metrics2");
Object1 object = new Object1(1.0, 2.0);
System.out.println(e.eval(object));
// -> 3.0
}

Related

invoke a get/set static operation from two different classes

I have 3 Classes: Regulate, Luminosity, Test
From the class Regulate, I which to setting an attribute in the class Luminosity by invoking the method setAttribute
Then in class Test, I calling the method getAttribute.
The problem is, When I calling the method getAttribute, I find a different value that I set it.
This is the Class Luminosity
public class Luminosity{
public static int attribute;
public static int getAttribute(){
return attribute;
}
public static void setAttribute(int v) {
attribute=v;
try {
File fichier = new File("../../WorkspaceSCA/Lamp/value.txt");
PrintWriter pw = new PrintWriter(new FileWriter(fichier)) ;
String ch=Integer.toString(attribute);
pw.append(ch);
pw.println();
pw.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
the Regulate Code:
public class Regulate {
public static void main(String[] args) throws InterruptedException {
Luminosity.setSensedValue(50));
System.out.println("Value of Luminosity= "+ Luminosity.getSensedValue());
}
}
this shows me: Value of Luminosity= 50
Now, I want to recover this value from a different class(Test), like this:
public class Test {
public static void main(String[] args) throws InterruptedException {
System.out.println("Value = "+ Luminosity.getSensedValue());
this shows me: Value= 0
I want to recover the same value.
Thank's in advance
You are start two different classes in two different threads.
Of course Luminosity doesn't have previous value, it was setting in different JVM.
If you want to setup an attribute and transfer it between two threads you can place it in a text file.
public class Luminosity {
private static final String FILE_NAME = "attribute.txt";
private int attribute;
public void writeAttribute(int val) throws IOException {
try (FileWriter fileWriter = new FileWriter(FILE_NAME)) {
fileWriter.append("" + val);
fileWriter.flush();
}
attribute = val;
}
public int readAttribute() throws IOException {
StringBuilder sb = new StringBuilder();
try (FileReader fileReader = new FileReader(FILE_NAME)) {
int r;
while (true) {
char[] buffer = new char[100];
r = fileReader.read(buffer);
if (r == -1) break;
sb.append(new String(Arrays.copyOf(buffer, r)));
}
} catch (FileNotFoundException e) {
return 0;
}
if (sb.length() == 0) return 0;
return Integer.parseInt(sb.toString());
}
public static void main(String[] args) throws IOException {
Luminosity luminosity = new Luminosity();
System.out.println("attribute after start: " + luminosity.readAttribute());
luminosity.writeAttribute(50);
System.out.println("new attribute: " + luminosity.readAttribute());
}
}

Set value in Setter according to number of column in ResultSetMetaData

I am looking for dynamic approach in order to set the values in setter method, in which I fetch the total number of column from ResultSetMetaData, on based of those result, I want to set the values in corresponding setter method. I already prepared the snippet in my utility class.
public Integer extractData(ResultSet rs) throws SQLException, DataAccessException {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for(int i = 1 ; i <= columnCount ; i++){
SQLColumn column = new SQLColumn();
String columnName = rsmd.getColumnName(i);
}
return columnCount;
}
Now the scenario is I want to set Pay_codes Of Employees, now there are total 95 paycode, but it differs in case of employees.
For example, Regular employees has 13 paycode, where as contactual employee has 6 codes, similarly society employees has 8 paycodes.
Now I need to show the list of paycodes on behalf of employee.
I passed EmployeeCode and I got the result.
Now The problem
whether I set all the column in my RowMapper like below
Paycode pc=new PayCode();
if(rs.getString("ESIC") != null){
pc.setESICCode(rs.getString("ESIC"));
}
if(rs.getString("EPF") != null){
pc.setEPFCode(rs.getString("EPF"));
}
if(rs.getString("Allowance") != null){
pc.setAllowance(rs.getString("Allowance"));
}
and many more columns........till 300+ lines
This seems very bad approach, because, Paycode can be increase or decrease as per client request.
So, I am looking for 2-3 line of dynamic code which set the values in setter according to the column name inside "ResultSetMetaData".So Kindly suggest me the best approach and help me to achieve the same.
However I am thinking of generic implementation, is generic do some magic, If yes > then how? please suggest me.
Use this code:
private void mapFields(PayCode p, String setterName, Object value) {
Method[] methods = PayCode.class.getDeclaredMethods();
for(Method method: methods){
if(method.getName().contains(setterName)){
try {
method.invoke(p, value);
break;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
So you use Java reflection API with PayCode.class.getDeclaredMethods to get class methods, and then you iterate through method names searching for method that contains name of the property.
Once you find it you set the value to the object with method.invoke(p, value), and exit the loop.
You can make things faster if you store PayCode.class.getDeclaredMethods(), and then make a hash set with method name as a key, and method as a value Map<String, Method>:
static Map<String, Method> mapFields(Class clazz) {
Method[] methods = clazz.getDeclaredMethods();
Map<String, Method> result = new HashMap<>();
for(Method method: methods){
String methodName = method.getName();
if(methodName.indexOf("set") == 0){
result.put(methodName.substring(3), method);
}
}
return result;
}
and then use it:
Map<String, Method> fields = mapFields(PayCode.class);
if(fields.containsKey(name)){
try {
fields.get(name).invoke(p, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
You can use reflection
package com.test;
import java.lang.reflect.Method;
class PayCode {
private String esic;
private String epf;
public String getEsic() {
return esic;
}
public void setEsic(String esic) {
this.esic = esic;
}
public String getEpf() {
return epf;
}
public void setEpf(String epf) {
this.epf = epf;
}
#Override
public String toString() {
return "PayCode [esic=" + esic + ", epf=" + epf + "]";
}
}
public class DynamicSetter {
public static void main(String[] args) {
PayCode payCode = new PayCode();
try {
/**
* Here you can take "set" hardcoded and generate suffix "Esic"
* dynamically, may be using apache StringUtils or implement using
* Substring, based on your class setter methods.
*/
Method esicMethod = PayCode.class.getMethod("set" + "Esic", String.class);
esicMethod.invoke(payCode, "Test Paycode");
System.out.println("Check paycode in object : " + payCode);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
You can use HashMap<> to add all pay code in that. You can also implement gtter for each pay code to read from HashMap.
package com.test;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
class Employee {
private Map<String, String> payCodes = new HashMap<>();
private String epf;
public String getEsic() {
return payCodes.get("ESIC");
}
public String getEpf() {
return payCodes.get("EPF");
}
public Map<String, String> getPayCodes() {
return payCodes;
}
}
public class DynamicSetter {
public static void main(String[] args) {
}
public static Integer extractData(ResultSet rs) throws SQLException, DataAccessException {
while(rs.next()) {
Employee e = new Employee();
Map<String, String> payCodes = e.getPayCodes();
//set app paycode in payCodes, you can use column name as key and fetch value from result set.
}
}
}

How to use eval via Jython?

I am trying to use the original eval in Python, via Jython.
But for some reason I don't understand, I am getting a NullPointerExec.
public static String Parse(String s)
{
ScriptEngine engine = new ScriptEngineManager().getEngineByName("python");
try
{
return engine.eval("eval('%s')".format(s)).toString();
}
catch (ScriptException e)
{
e.printStackTrace();
}
return "--";
}
You can use Pythons eval function through Java (and Jython) like this:
public static boolean XLargerThanY(int x, int y) throws ScriptException {
PyScriptEngineFactory factory = new PyScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine();
PyFunction function = (PyFunction) engine.eval("x > y");
PyBoolean ans = (PyBoolean) function.__call__(new PyInteger(x), new PyInteger(y));
return ans.getBooleanValue();
}

How to log parameters passed to a method programatically in Java

How can I log the parameters passed to a method at runtime ? Is there any Java library for this or any any exception that can be raised to monitor it ?
You can use javassist's ProxyFactory or Translator to change to print the arguments at runtime:
Using Translator (with a new ClassLoader):
public static class PrintArgumentsTranslator implements Translator {
public void start(ClassPool pool) {}
#Override
public void onLoad(ClassPool pool, String cname)
throws NotFoundException, CannotCompileException {
CtClass c = pool.get(cname);
for (CtMethod m : c.getDeclaredMethods())
insertLogStatement(c, m);
for (CtConstructor m : c.getConstructors())
insertLogStatement(c, m);
}
private void insertLogStatement(CtClass c, CtBehavior m) {
try {
List<String> args = new LinkedList<String>();
for (int i = 0; i < m.getParameterTypes().length; i++)
args.add("$" + (i + 1));
String toPrint =
"\"----- calling: "+c.getName() +"." + m.getName()
+ args.toString()
.replace("[", "(\" + ")
.replace(",", " + \", \" + ")
.replace("]", "+\")\"");
m.insertBefore("System.out.println("+toPrint+");");
} catch (Exception e) {
// ignore any exception (we cannot insert log statement)
}
}
}
*Note that you need to change the default ClassLoader so that you can instrument the classes, so before calling your main you need some inserted the following code:
public static void main(String[] args) throws Throwable {
ClassPool cp = ClassPool.getDefault();
Loader cl = new Loader(cp);
cl.addTranslator(cp, new PrintArgumentsTranslator());
cl.run("test.Test$MyApp", args); // or whatever class you want to start with
}
public class MyApp {
public MyApp() {
System.out.println("Inside: MyApp constructor");
}
public static void main(String[] args) {
System.out.println("Inside: main method");
new MyApp().method("Hello World!", 4711);
}
public void method(String string, int i) {
System.out.println("Inside: MyApp method");
}
}
Outputs:
----- calling: test.Test$MyApp.main([Ljava.lang.String;#145e044)
Inside: main method
----- calling: test.Test$MyApp.Test$MyApp()
Inside: MyApp constructor
----- calling: test.Test$MyApp.method(Hello World!, 4711)
Inside: MyApp method
Using ProxyFactory
public class Test {
public String method(String string, int integer) {
return String.format("%s %d", string, integer);
}
public static void main(String[] args) throws Exception {
ProxyFactory f = new ProxyFactory();
f.setSuperclass(Test.class);
Class<?> c = f.createClass();
MethodHandler mi = new MethodHandler() {
public Object invoke(
Object self, Method m, Method proceed, Object[] args)
throws Throwable {
System.out.printf("Method %s called with %s%n",
m.getName(), Arrays.toString(args));
// call the original method
return proceed.invoke(self, args);
}
};
Test foo = (Test) c.newInstance();
((Proxy) foo).setHandler(mi);
foo.method("Hello", 4711);
}
}
Output:
Method method called with [Hello, 4711]
You should try to use AOP. Here is an example that does more or less what you want: How to use AOP with AspectJ for logging?
I think you can register your MBean then only you will be able to check using JMX.
Link: http://docs.oracle.com/cd/E19159-01/819-7758/gcitp/index.html

How can I introspect a freemarker template to find out what variables it uses?

I'm not at all sure that this is even a solvable problem, but supposing that I have a freemarker template, I'd like to be able to ask the template what variables it uses.
For my purposes, we can assume that the freemarker template is very simple - just "root level" entries (the model for such a template could be a simple Map). In other words, I don't need to handle templates that call for nested structures, etc.
one other way to get the variables from java. This just tries to process the template and catch the InvalidReferenceException to find all the variables in a freemarker-template
/**
* Find all the variables used in the Freemarker Template
* #param templateName
* #return
*/
public Set<String> getTemplateVariables(String templateName) {
Template template = getTemplate(templateName);
StringWriter stringWriter = new StringWriter();
Map<String, Object> dataModel = new HashMap<>();
boolean exceptionCaught;
do {
exceptionCaught = false;
try {
template.process(dataModel, stringWriter);
} catch (InvalidReferenceException e) {
exceptionCaught = true;
dataModel.put(e.getBlamedExpressionString(), "");
} catch (IOException | TemplateException e) {
throw new IllegalStateException("Failed to Load Template: " + templateName, e);
}
} while (exceptionCaught);
return dataModel.keySet();
}
private Template getTemplate(String templateName) {
try {
return configuration.getTemplate(templateName);
} catch (IOException e) {
throw new IllegalStateException("Failed to Load Template: " + templateName, e);
}
}
This is probably late, but in case anyone else encountered this problem : you can use 'data_model' and 'globals' to inspect the model - data_model will only contain values provided by the model while globals will also contain any variables defined in the template.
You need to prepend the special variables with a dot - so to access globals, use ${.globals}
For other special variables see http://freemarker.sourceforge.net/docs/ref_specvar.html
I had the same task to get the list of variables from template on java side and don't found any good approaches to that except using reflection. I'm not sure whether there is a better way to get this data or not but here's my approach:
public Set<String> referenceSet(Template template) throws TemplateModelException {
Set<String> result = new HashSet<>();
TemplateElement rootTreeNode = template.getRootTreeNode();
for (int i = 0; i < rootTreeNode.getChildCount(); i++) {
TemplateModel templateModel = rootTreeNode.getChildNodes().get(i);
if (!(templateModel instanceof StringModel)) {
continue;
}
Object wrappedObject = ((StringModel) templateModel).getWrappedObject();
if (!"DollarVariable".equals(wrappedObject.getClass().getSimpleName())) {
continue;
}
try {
Object expression = getInternalState(wrappedObject, "expression");
switch (expression.getClass().getSimpleName()) {
case "Identifier":
result.add(getInternalState(expression, "name").toString());
break;
case "DefaultToExpression":
result.add(getInternalState(expression, "lho").toString());
break;
case "BuiltinVariable":
break;
default:
throw new IllegalStateException("Unable to introspect variable");
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new TemplateModelException("Unable to reflect template model");
}
}
return result;
}
private Object getInternalState(Object o, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getDeclaredField(fieldName);
boolean wasAccessible = field.isAccessible();
try {
field.setAccessible(true);
return field.get(o);
} finally {
field.setAccessible(wasAccessible);
}
}
Sample project that I made for demonstrating template introspection can be found on github: https://github.com/SimY4/TemplatesPOC.git
I solved this for my very simple usecase (only using flat datastructure, no nesting (for example: ${parent.child}), lists or more specific) with dummy data provider:
public class DummyDataProvider<K, V> extends HashMap<K, V> {
private static final long serialVersionUID = 1;
public final Set<String> variables = new HashSet<>();
#SuppressWarnings("unchecked")
#Override
public V get(Object key) {
variables.add(key.toString());
return (V) key;
}
}
You can give this for processing to a template and when it finishes Set variables contains your variables.
This is very simplistic approach, which certainly needs improvement, but you get the idea.
public static Set<String> getNecessaryTemplateVariables(String templateName) throws TemplateModelException {
Set<String> result = new HashSet<>();
TemplateElement rootTreeNode = getTemplate(templateName).getRootTreeNode();
if ("IteratorBlock".equals(rootTreeNode.getClass().getSimpleName())) {
introspectFromIteratorBlock(result, rootTreeNode);
return result;
}
for (int i = 0; i < rootTreeNode.getChildCount(); i++) {
TemplateModel templateModel = rootTreeNode.getChildNodes().get(i);
if (!(templateModel instanceof StringModel)) {
continue;
}
Object wrappedObject = ((StringModel) templateModel).getWrappedObject();
if ("DollarVariable".equals(wrappedObject.getClass().getSimpleName())) {
introspectFromDollarVariable(result, wrappedObject);
} else if ("ConditionalBlock".equals(wrappedObject.getClass().getSimpleName())) {
introspectFromConditionalBlock(result, wrappedObject);
} else if ("IfBlock".equals(wrappedObject.getClass().getSimpleName())) {
introspectFromIfBlock(result, wrappedObject);
} else if ("IteratorBlock".equals(wrappedObject.getClass().getSimpleName())) {
introspectFromIteratorBlock(result, wrappedObject);
}
}
return result;
}
private static void introspectFromIteratorBlock(Set<String> result, Object wrappedObject) {
try {
Object expression = getInternalState(wrappedObject, "listExp");
result.add(getInternalState(expression, "name").toString());
} catch (NoSuchFieldException | IllegalAccessException ignored) {
}
}
private static void introspectFromConditionalBlock(Set<String> result, Object wrappedObject)
throws TemplateModelException {
try {
Object expression = getInternalState(wrappedObject, "condition");
if (expression == null) {
return;
}
result.addAll(dealCommonExpression(expression));
String nested = getInternalState(wrappedObject, "nestedBlock").toString();
result.addAll(getNecessaryTemplateVariables(nested));
} catch (NoSuchFieldException | IllegalAccessException ignored) {
}
}
private static Set<String> dealCommonExpression(Object expression)
throws NoSuchFieldException, IllegalAccessException {
Set<String> ret = Sets.newHashSet();
switch (expression.getClass().getSimpleName()) {
case "ComparisonExpression":
String reference = dealComparisonExpression(expression);
ret.add(reference);
break;
case "ExistsExpression":
reference = dealExistsExpression(expression);
ret.add(reference);
break;
case "AndExpression":
ret.addAll(dealAndExpression(expression));
default:
break;
}
return ret;
}
private static String dealComparisonExpression(Object expression)
throws NoSuchFieldException, IllegalAccessException {
Object left = getInternalState(expression, "left");
Object right = getInternalState(expression, "right");
String reference;
if ("Identifier".equals(left.getClass().getSimpleName())) {
reference = getInternalState(left, "name").toString();
} else {
reference = getInternalState(right, "name").toString();
}
return reference;
}
private static String dealExistsExpression(Object expression) throws NoSuchFieldException, IllegalAccessException {
Object exp = getInternalState(expression, "exp");
return getInternalState(exp, "name").toString();
}
private static Set<String> dealAndExpression(Object expression) throws NoSuchFieldException,
IllegalAccessException{
Set<String> ret = Sets.newHashSet();
Object lho = getInternalState(expression, "lho");
ret.addAll(dealCommonExpression(lho));
Object rho = getInternalState(expression, "rho");
ret.addAll(dealCommonExpression(rho));
return ret;
}
private static void introspectFromIfBlock(Set<String> result, Object wrappedObject)
throws TemplateModelException {
result.addAll(getNecessaryTemplateVariables(wrappedObject.toString()));
}
private static void introspectFromDollarVariable(Set<String> result, Object wrappedObject)
throws TemplateModelException {
try {
Object expression = getInternalState(wrappedObject, "expression");
switch (expression.getClass().getSimpleName()) {
case "Identifier":
result.add(getInternalState(expression, "name").toString());
break;
case "DefaultToExpression":
result.add(getInternalState(expression, "lho").toString());
break;
case "BuiltinVariable":
break;
default:
break;
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new TemplateModelException("Unable to reflect template model");
}
}
private static Object getInternalState(Object o, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field [] fieldArray = o.getClass().getDeclaredFields();
for (Field field : fieldArray) {
if (!field.getName().equals(fieldName)) {
continue;
}
boolean wasAccessible = field.isAccessible();
try {
field.setAccessible(true);
return field.get(o);
} finally {
field.setAccessible(wasAccessible);
}
}
throw new NoSuchFieldException();
}
private static Template getTemplate(String templateName) {
try {
StringReader stringReader = new StringReader(templateName);
return new Template(null, stringReader, null);
} catch (IOException e) {
throw new IllegalStateException("Failed to Load Template: " + templateName, e);
}
}
I optimized SimY4's answer, and supported <#list> and <#if> block. Code is not fully tested
Execute following regex on the template:
(?<=\$\{)([^\}]+)(?=\})
(?<=\$\{) Matches everything followed by ${
([^\}]+) Matches any string not containing }
(?=\}) Matches everything before }
I had the same problem and none of posted solution made sense to me. What I came with is plugging custom implementation of
TemplateExceptionHandler. Example:
final private List<String> missingReferences = Lists.newArrayList();
final Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
cfg.setTemplateExceptionHandler(new TemplateExceptionHandler() {
#Override
public void handleTemplateException(TemplateException arg0, Environment arg1, Writer arg2) throws TemplateException {
if (arg0 instanceof InvalidReferenceException) {
missingReferences.add(arg0.getBlamedExpressionString());
return;
}
throw arg0;
}
}
Template template = loadTemplate(cfg, templateId, templateText);
StringWriter out = new StringWriter();
try {
template.process(templateData, out);
} catch (TemplateException | IOException e) {
throw new RuntimeException("oops", e);
}
System.out.println("Missing references: " + missingReferences);
Read more here: https://freemarker.apache.org/docs/pgui_config_errorhandling.html

Categories

Resources