
com.api.jsonata4java.Expression Maven / Gradle / Ivy
/**
*
*/
package com.api.jsonata4java;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.api.jsonata4java.expressions.EvaluateException;
import com.api.jsonata4java.expressions.EvaluateRuntimeException;
import com.api.jsonata4java.expressions.Expressions;
import com.api.jsonata4java.expressions.ExpressionsVisitor;
import com.api.jsonata4java.expressions.FrameEnvironment;
import com.api.jsonata4java.expressions.ParseException;
import com.api.jsonata4java.expressions.functions.DeclaredFunction;
import com.api.jsonata4java.expressions.generated.MappingExpressionParser.ExprContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.TextNode;
/**
* Class to provide embedding and extending JSONata features
*/
public class Expression {
/**
* Genearte a new Expression based on evaluating the supplied expression
*
* @param expression
* the logic to be parsed for later execution via the evaluate
* methods
* @return new Expression object
* @throws ParseException
* @throws IOException
*/
public static Expression jsonata(String expression) throws ParseException, IOException {
return new Expression(expression);
}
/**
* Testing the various methods based on
* https://docs.jsonata.org/embedding-extending#expressionregisterfunctionname-implementation-signature
*
* @param args
* not used
*/
public static void main(String[] args) {
try {
String exprString = "$sum(example.value)";
String inputString = "{\"example\": [{\"value\": 4}, {\"value\": 7}, {\"value\": 13}]}";
System.out.println("Expression is " + exprString);
System.out.println("Input is " + inputString);
Expression expression = Expression.jsonata(exprString);
JsonNode obj = new ObjectMapper().readTree(inputString);
JsonNode result = expression.evaluate(obj);
System.out.println("Result is " + result);
expression = Expression.jsonata("$a +$b()");
expression.assign("a", "4");
expression.assign("$b", "function(){1}");
result = expression.evaluate(obj);
System.out.println("Input is \"$a + $b()\" with assignments \"a\":4, \"$b\":\"function(){1}\"");
System.out.println("Result is " + result);
JsonNode bindingObj = new ObjectMapper().readTree("{\"a\":4, \"b\":\"function(){78}\"}");
System.out.println("Input is \"$a + $b()\" with binding object: " + bindingObj.toString());
System.out.println("Result is " + Expression.jsonata("$a + $b()").evaluate(obj, bindingObj));
bindingObj = new ObjectMapper().readTree("{\"a\":4, \"b\":\"function($c){$c+78}\",\"c\":7}");
System.out.println("Input is \"$a + $b($c)\" with binding object: " + bindingObj.toString());
System.out.println("Result is " + Expression.jsonata("$a + $b($c)").evaluate(obj, bindingObj));
try {
expression = Expression.jsonata("$notafunction()");
result = expression.evaluate(JsonNodeFactory.instance.objectNode());
throw new Exception("Expression " + expression + " should have generated an exception");
} catch (EvaluateRuntimeException ere) {
System.out
.println("Result is we got the expected EvaluateRuntimeException for " + ere.getLocalizedMessage());
}
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (EvaluateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
ExpressionsVisitor _eval = null;
Expressions _expr = null;
FrameEnvironment _environment = new FrameEnvironment(null);
Map _declaredFunctionMap = new HashMap();
Map _variableMap = new HashMap();
/**
* Constructor for Expression
*
* @param expression
* the logic to be parsed for later execution via evaluate
* methods
* @throws ParseException
* @throws IOException
*/
public Expression(String expression) throws ParseException, IOException {
_expr = Expressions.parse(expression);
_eval = _expr.getExpr();
}
/**
* Assign the binding to the environment preparing for evaluation
*
* @param binding
*/
public void assign(Binding binding) {
if (binding.getType() == BindingType.VARIABLE) {
_variableMap.put(binding.getVarName(), binding.getExpression());
} else {
_declaredFunctionMap.put(binding.getVarName(), binding.getFunction());
}
}
/**
* Assign the expression (variable or function declaration) to the variable name
* supplied
*
* @param varname
* name of the variable to map to a variable expression or
* function declaration expression
* @param expression
* logic to be assigned to the variable name
* @throws ParseException
* @throws IOException
*/
public void assign(String varname, String expression) throws ParseException, IOException {
Binding binding = new Binding(varname, expression);
assign(binding);
}
/**
* Generate a result form the Expression's parsed expression and variable
* assignments or registered functions
*
* @param rootContext
* JSON object specifying the content used to evaluate the
* expression
* @return the result from executing the Expression's parsed expression and
* variable assignments or registered functions
* @throws EvaluateException
* @throws ParseException
*/
public JsonNode evaluate(JsonNode rootContext) throws EvaluateException, ParseException {
ExpressionsVisitor eval = new ExpressionsVisitor(rootContext,new FrameEnvironment(null));
// process any stored bindings
for (Iterator it = _variableMap.keySet().iterator(); it.hasNext();) {
String key = it.next();
ExprContext ctx = _variableMap.get(key);
eval.setVariable(key, eval.visit(ctx));
}
for (Iterator it = _declaredFunctionMap.keySet().iterator(); it.hasNext();) {
String key = it.next();
DeclaredFunction fct = _declaredFunctionMap.get(key);
eval.setDeclaredFunction(key, fct);
}
return eval.visit(_expr.getTree());
}
/**
* Generate a result form the Expression's parsed expression and variable
* assignments or registered functions specified in the list of bindings
*
* @param rootContext
* JSON object specifying the content used to evaluate the
* expression
* @param bindings
* assignments of variable names to variable expressions or
* function declarations
* @return the result from executing the Expression's parsed expression and
* variable assignments or registered functions specified in the list of
* bindings
* @throws EvaluateException
* @throws ParseException
*/
public JsonNode evaluate(JsonNode rootContext, List bindings) throws EvaluateException, ParseException {
JsonNode result = null;
// first do variables
for (Binding binding : bindings) {
assign(binding);
}
result = evaluate(rootContext);
return result;
}
/**
* Generate a result form the Expression's parsed expression and variable
* assignments or registered functions specified in the bindings object
*
* @param rootContext
* JSON object specifying the content used to evaluate the
* expression
* @param bindingObj
* a JSON object containing the assignments of variable names
* to variable expressions or function declarations
* @return the result from executing the Expression's parsed expression and
* variable assignments or registered functions specified in the
* bindings object
* @throws EvaluateException
* @throws ParseException
* @throws IOException
*/
public JsonNode evaluate(JsonNode rootContext, JsonNode bindingObj) throws EvaluateException, ParseException, IOException {
List bindings = new ArrayList();
for (Iterator it = bindingObj.fieldNames(); it.hasNext();) {
String key = it.next();
Object testObj = bindingObj.get(key);
String expression = "";
if (testObj instanceof TextNode == false) {
expression = testObj.toString();
} else {
expression = ((TextNode) testObj).asText();
}
Binding binding = new Binding(key, expression);
bindings.add(binding);
}
return evaluate(rootContext, bindings);
}
/**
* Registers a function implementation (declaration) by name
*
* @param fctName
* the name of the function
* @param implementation
* the function declaration
* @throws ParseException
* @throws IOException
*/
public void registerFunction(String fctName, String implementation) throws ParseException, IOException {
Binding fctBinding = new Binding(fctName, implementation);
_declaredFunctionMap.put(fctBinding.getVarName(), fctBinding.getFunction());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy