Considering Tim's suggestiom, I'm thinking about modifying the interface in
following way:
So there will be 3 interfaces:
public interface Expression<O>
{
O execute(Object... obj);
}
public interface ExpressionEvaluator
{
<O> ExpressionEvaluator.Expression<O> createExecutableFunction(String
expression, Class<?> returnType);
<O> ExpressionEvaluator.Expression<O> createExecutableExpression(String
expression, Class<?> returnType);
void setExpressionParser(ExpressionParser parser);
}
public interface ExpressionParser
{
String convertToCompilableExpression(String expression, Class<?>
returnType, boolean containsReturnStatement);
}
Description of interfaces:
1. Expression interface is the final output which will have executable code
of expression.
2. ExpressionEvaluator interface will be implemented for specific type if
implementation. For eg. In this case the concrete implementation will be
JavaExpressionEvaluator which will evaluate quasi-Java expression
3. ExpressionParser interface will defined how expression need to be parsed
and can be plugin to ExpressionEvaluator interface via setExpressionParser
method.
This way,
1. One can override parsing logic for specific evaluator.
2. Override the expression evaluation logic all together.
3. Sticking to a common interface of ExpressionEvaluator & Expression will
make the user code not to change even if parser or evaluator changes.
Thoughts?
Thanks,
Chinmay.
On Thu, Jan 14, 2016 at 2:17 PM, Chinmay Kolhatkar <[email protected]>
wrote:
> I think think is doable.
> I'll take a look.
>
> Thanks,
> Chinmay.
>
> On Thu, Jan 14, 2016 at 1:59 PM, Timothy Farkas <[email protected]>
> wrote:
>
>> Haven't gone though you're PR, so I'm not sure how this would fit in. But
>> I
>> think introducing an interface like below, and allowing it to be set may
>> be
>> sufficient.
>>
>> public interface ExpressionParser
>> {
>> public String convertToJavaExpression(String expression);
>> }
>>
>> Thanks,
>> Tim
>>
>> On Thu, Jan 14, 2016 at 12:19 AM, Chinmay Kolhatkar <
>> [email protected]
>> > wrote:
>>
>> > Ah got it. That's a good point. Maybe its good to separate the parsing
>> and
>> > compilation part of the evaluation.
>> > And let one override the parsing logic.
>> >
>> > I'll see how to incorporate that, but if you have idea about achieving
>> it,
>> > please share it.
>> >
>> > Thanks,
>> > Chinmay.
>> >
>> >
>> > On Thu, Jan 14, 2016 at 1:43 PM, Timothy Farkas <[email protected]>
>> > wrote:
>> >
>> > > Hey Chinmay,
>> > >
>> > > It is possible the user may want to define a syntax radically
>> different
>> > > from Java style syntax. I've proposed a syntax similar to yours to
>> one of
>> > > our users for expression evaluation but they didn't like it because
>> the
>> > > syntax needs to be something easily validated by a UI. It may be
>> possible
>> > > that the user wants expressions to be sent to an operator as json,
>> > because
>> > > that is easy to parse and validate in javascript:
>> > >
>> > > {"param":"myField1","operation":">","threshold":"1"}
>> > >
>> > > If the syntax is pluggable then an implementation of this syntax
>> could be
>> > > swapped with with an implementation of the syntax you've already
>> provided
>> > > without changing operator code.
>> > >
>> > > Thanks,
>> > > Tim
>> > >
>> > > On Wed, Jan 13, 2016 at 11:34 PM, Chinmay Kolhatkar <
>> > > [email protected]
>> > > > wrote:
>> > >
>> > > > Hi tim,
>> > > >
>> > > > I agree with you. The expression here we're talking about is really
>> a
>> > > > quasi-Java expression. One can do anything which java does.
>> > > > Only change with java syntax here is how variables are accessed.
>> > > >
>> > > > They're by default accessed as ${...}.
>> > > >
>> > > > But this is also made configurable via a setter property on
>> > > > ExpressionEvaluator. The pull request has it.
>> > > >
>> > > > If this is what you're talking about then this is taken care of.
>> > > >
>> > > > Thanks,
>> > > > Chinmay.
>> > > >
>> > > >
>> > > > On Thu, Jan 14, 2016 at 1:00 PM, Timothy Farkas <
>> [email protected]>
>> > > > wrote:
>> > > >
>> > > > > Hi Chinmay,
>> > > > >
>> > > > > I think this is a very good first implementation. My only concern
>> is
>> > > that
>> > > > > people will get caught up in the details of the syntax for this
>> > > > expression
>> > > > > language. I think a way to avoid that is to make the syntax
>> > pluggable.
>> > > > For
>> > > > > example is there an interface for expression evaluation which can
>> be
>> > > > > implemented by different syntaxes? This would allow operators
>> which
>> > use
>> > > > > expression evaluation to have the syntax configured via a
>> property.
>> > > That
>> > > > > way if someone discovers a limitation in the syntax down the
>> line, a
>> > > new
>> > > > > syntax can be introduced without breaking backwards compatibility
>> and
>> > > > > without requiring operator code to be changed.
>> > > > >
>> > > > > Thanks,
>> > > > > Tim
>> > > > >
>> > > > > On Wed, Jan 13, 2016 at 10:52 PM, Chinmay Kolhatkar <
>> > > > > [email protected]
>> > > > > > wrote:
>> > > > >
>> > > > > > Hi All,
>> > > > > >
>> > > > > > I'm working on APEXCORE-1972 which adds support for a quasi-Java
>> > > > > Expression
>> > > > > > Language and its expression evaluator.
>> > > > > >
>> > > > > > All the detailed functionality and design details along with
>> > examples
>> > > > are
>> > > > > > present in Jira.
>> > > > > >
>> > > > > > I've summarized the ExpressionEvaluator feature & Expression
>> > language
>> > > > > > below.
>> > > > > >
>> > > > > > The pull request created for this at here:
>> > > > > > https://github.com/apache/incubator-apex-malhar/pull/170
>> > > > > >
>> > > > > > Please share your thought on this.
>> > > > > >
>> > > > > > Thanks,
>> > > > > > Chinmay.
>> > > > > >
>> > > > > >
>> > > > > > *Summary of functionality of ExpressionEvaluator:*
>> > > > > >
>> > > > > > 1. Support quasi-Java Expression which defines a single line
>> > > > > executable
>> > > > > > expression
>> > > > > > 2. Support for quasi-Java expression based function code,
>> which
>> > > will
>> > > > > be
>> > > > > > compiled on the fly and made available for execution.
>> > > > > > 3. Should support accessing multiple fields from multiples
>> input
>> > > > POJOs
>> > > > > > while addressing the conversion of private variables to
>> public
>> > > > getter
>> > > > > > method for all levels.
>> > > > > > 4. Should support nested field support
>> > > > > > 5. quasi-Java expressions should support operands to be
>> > mentioned
>> > > in
>> > > > > > following ways:
>> > > > > > - ${input.fieldName}
>> > > > > > - Access fieldName via a object name.
>> > > > > > - ${fieldName}
>> > > > > > - Accessing fieldName directly when a single object is
>> > > > > registered
>> > > > > > for operation.
>> > > > > > - ${input}
>> > > > > > - Accessing object variable directly
>> > > > > > - ${input.fieldName.internalField}
>> > > > > > - Accessing nested fields
>> > > > > > 6. There should be some predefined function provided to
>> > > > expression
>> > > > > > writer which one can directly use in expression for invoking
>> > > certain
>> > > > > > functionality.
>> > > > > > 7. These are simple String based, Date time based etc
>> functions.
>> > > > > > 8. On-need-basic one should be able to easily update
>> Expression
>> > > > > > Evaluator to easily add new predefined functions to be made
>> > > > available
>> > > > > > for
>> > > > > > expression writer.
>> > > > > > 9. User of ExpressionEvaluator should be able to add a custom
>> > > method
>> > > > > > externally to be made available to in expression.
>> > > > > > 10. Though operands are defined, placeholder for the operand
>> in
>> > > > > > expression should be allowed to be overridden. By default,
>> > > > expression
>> > > > > > language should support bash type syntax for operand - {…}
>> > > > > > 11. The library should not introduce any serialization
>> related
>> > > > issues.
>> > > > > > 12. All the java operators should be supported.
>> > > > > >
>> > > > > >
>> > > > > >
>> > > > > > *The examples of quasi-Java Expression:*
>> > > > > >
>> > > > > > - ${inp.field1}
>> > > > > > - Will return value of field1 from registered input POJO.
>> > > > > > - ${inp.field1} + ${inp.field2}
>> > > > > > - Will return sum of field1 & field2 from given POJO
>> > > > > > - ${field1} + ${field2}
>> > > > > > - Equivalent to above
>> > > > > > - ${inpA.field1} > ${inpA.field2} ? ${inpA.field3} :
>> > > ${inpB.field3}
>> > > > > > - Executes ternary expression and returns value
>> accordingly.
>> > > > Works
>> > > > > on
>> > > > > > 2 POJOs. inpA & inpB are two placeholder registered for
>> given
>> > > > POJO
>> > > > > > with
>> > > > > > ExpressionEvaluator library.
>> > > > > > - pow(${inpA.field1}, ${inpB.field2})
>> > > > > > - Executes pow function coming from java.lang.Math
>> library.
>> > > This
>> > > > > and
>> > > > > > other with lot other basic functions is available to
>> > expression
>> > > > > > writer out
>> > > > > > of the box to use in expression.
>> > > > > > - ${inpA.field1} > 0 ? ${inpB.innerPOJO.field3} :
>> > > > > > ${inpA.innerPOJO.field3}
>> > > > > > - Shows how nested POJOs can be accessed in expression.
>> The
>> > > > > variables
>> > > > > > will evaluate to correct public getter method is required.
>> > > > > > - ${inp.firstname} + “ “ + ${inp.lastname}
>> > > > > > - Generate the full name as per given expression from
>> > firstname
>> > > > and
>> > > > > > lastname field.
>> > > > > > - long retVal=1; for (int i=0; ${inpF.value1}; i++) {retVal =
>> > > > retVal *
>> > > > > > ${inpF.value1}; } return retVal;
>> > > > > > - This tells a complete method content to
>> > ExpressionEvaluator.
>> > > > The
>> > > > > > library create an executable and compiled method using
>> this
>> > > > > > expression.
>> > > > > >
>> > > > > >
>> > > > > >
>> > > > >
>> > > >
>> > >
>> >
>>
>
>