[
https://issues.apache.org/jira/browse/APEXMALHAR-1972?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15096108#comment-15096108
]
ASF GitHub Bot commented on APEXMALHAR-1972:
--------------------------------------------
Github user shubham-pathak22 commented on a diff in the pull request:
https://github.com/apache/incubator-apex-malhar/pull/170#discussion_r49583885
--- Diff:
library/src/main/java/com/datatorrent/lib/expressions/ExpressionEvaluator.java
---
@@ -0,0 +1,440 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.datatorrent.lib.expressions;
+
+import org.codehaus.commons.compiler.CompilerFactoryFactory;
+import org.codehaus.commons.compiler.IScriptEvaluator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class is used for evaluating expressions which takes multiple
parameter object and the result is returned for that expression.
+ *
+ * The way to reference a variable in an object is ${placeholder.varname}.
+ * The variable will be resolved to its accessible variable or getter
method in order. After this the variable can be used as if its a Java variable.
+ *
+ * ExpressionEvaluator also allows you to set extra imports that needs to
be added over default is java.lang.*
+ *
+ * ExpressionEvaluator needs to be configured with following
configurations as minimal configuration:
+ * 1. Mapping of input object place holders to it corresponding types.
+ * This can be done with setInputObjectPlaceholders method.
+ * 2. Return type of of expression evaluation.
+ * 3. Expression to be evaluated. This is a standard java expression
except for referencing the variable inside object JEL syntax needs to be used
i.e. ${objectPlaceHolder.varName}
+ *
+ * Expression cab be defined as per JSL 7 syntax:
+ * http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html
+ */
+public class ExpressionEvaluator
+{
+ private static final Logger logger =
LoggerFactory.getLogger(ExpressionEvaluator.class);
+
+ private static final String INP_OBJECT_FUNC_VAR = "obj";
+
+ private static final String GET = "get";
+ private static final String IS = "is";
+
+ private final Map<String, Class> placeholderClassMapping = new
HashMap<>();
+ private final Map<String, Integer> placeholderIndexMapping = new
HashMap<>();
+ private final Set<String> imports = new HashSet<>();
+ private String variablePlaceholderPattern = "\\$\\{(.*?)\\}";
+
+
+ /**
+ * Constructor for ExpressionEvaluator.
+ * This constructor will add some default java imports for expressions
to be compiled.
+ */
+ public ExpressionEvaluator()
+ {
+ addDefaultImports();
+ }
+
+ /**
+ * This is the Expression interface, object of which will be returned to
the evaluated expression.
+ * The person who want to execute the expression is expected to run the
execute method with parameters in the same order
+ * as set in setInputObjectPlaceholders method.
+ *
+ * @param <O> This is generic class return type of execute method of
expression.
+ */
+ public interface Expression<O>
+ {
+ O execute(Object... obj);
+ }
+
+ /**
+ * This method of ExpressionEvaluator will create a compiled &
executable expression which is go as-is as method's content.
+ * The expression provided here is expected to contain a return
statement.
+ * If expression does not contain return statement, the method will
throw RuntimeException.
+ *
+ * <p>
+ * Example is as follows:
+ * Let the expression be <func_expression>
+ * After compiling and resolving the placeholder, it becomes
<compiled_func_expression>
+ *
+ * The execute method of Expression interface would look like this:
+ * <return_type> execute(Object... obj)
+ * {
+ * <compiled_func_expression>
+ * }
+ * </p>
+ *
+ * @param expression String expression which has return statement in it.
+ * @param returnType Type of class which will be returned by execute
method of Expression interface.
+ * @param <O> Parameterized return class type of expression
after evaluation.
+ * @return Object of type Expression interface having
compiled and executable expression.
+ */
+ public <O> Expression<O> createExecutableFunction(String expression,
Class<?> returnType)
+ {
+ return createExecutableCode(expression, returnType, true);
+ }
+
+
+ /**
+ * This method of ExpressionEvaluator will create a compiled &
executable expression to which return statement is added.
+ * The expression provided here is not expected to contain a return
statement.
+ * Expression should be a single line expression as per JLS 7 as given
in:
+ * <a>https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html</a>
+ *
+ * <p>
+ * Example is as follows:
+ * Let the expression be <expression>
+ * After compiling and resolving the placeholder, it becomes
<compiled_expression>
+ *
+ * The execute method of Expression interface would look like this:
+ * <return_type> execute(Object... obj)
+ * {
+ * return ((<return_type>)(<compiled_expression>))
+ * }
+ * </p>
+ *
+ * @param expression String expression which has return statement in it.
+ * @param returnType Type of class which will be returned by execute
method of Expression interface.
+ * @param <O> Parameterized return class type of expression
after evaluation.
+ * @return Object of type Expression interface having
compiled and executable expression.
+ */
+ public <O> Expression<O> createExecutableExpression(String expression,
Class<?> returnType)
+ {
+ return createExecutableCode(expression, returnType, false);
+ }
+
+ /**
+ * This is a private which will be called by public method
createExecutableExpression & createExecutableFunction.
+ * This method is the main method which converts the given expression
into java expression format and compiles it
+ * using Janino.
+ *
+ * The method works in following steps:
+ * <ol>
+ * <li>Resolve object/variable placeholder to respective types and
replace them in expression</li>
+ * <li>Generate final code to go into execute method of Expression
class. Here the final code is generated based
+ * on whether the containsReturnStatement is true OR false. If its
true, the code is added as it is
+ * If false, it'll added along with return statement.</li>
+ * <li>Compile the expression using Janino library</li>
+ * <li>Return an object of type Expression which contains compiled
expression.</li>
+ * </ol>
+ *
+ * @param expression String expression that needs to be
compiled
+ * @param returnType Return type of the expression.
+ * @param containsReturnStatement Whether the expression contains return
statement OR not.
+ * @param <O> Parameterized return class type of
expression after evaluation.
+ * @return Object of type Expression interface
having compiled and executable expression.
+ */
+ @SuppressWarnings({"unchecked"})
+ private <O> Expression<O> createExecutableCode(String expression,
Class<?> returnType,
+ boolean containsReturnStatement)
+ {
+ if (this.placeholderClassMapping.size() <= 0) {
+ throw new RuntimeException("Mapping needs to be provided.");
+ }
+
+ Pattern entry = Pattern.compile(variablePlaceholderPattern);
+ Matcher matcher = entry.matcher(expression);
--- End diff --
Should we consider throwing runtime exception if expression is null / blank
?
> Create Expression Evaluator Support quasi-Java Expression Language
> ------------------------------------------------------------------
>
> Key: APEXMALHAR-1972
> URL: https://issues.apache.org/jira/browse/APEXMALHAR-1972
> Project: Apache Apex Malhar
> Issue Type: New Feature
> Components: utilities
> Reporter: Chinmay Kolhatkar
> Assignee: Chinmay Kolhatkar
>
> Create Expression Evaluator utility which will have support for quasi-Java
> expression language.
> Usecases, Design, etc need to be added as a comment.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)