a fork of EvalEx by ezylang with a handful of breaking changes

Add reflective test.

+82 -1
+9 -1
README.md
··· 1 EvalEx - Java Expression Evaluator 2 ========== 3 4 - This is a personal fork of EvalEx with lots of incompatible changes. 5 6 Please check out the original repo here on [GitHub](https://github.com/ezylang/EvalEx). 7 8 Changes over upstream: 9 10 - Inlining of simple and constant expressions. 11 - Immutable contexts and expressions. 12 - Replaced expression-wide variables with `evaluate` only parameters. 13 - `Object[]` in various places to allow passing arbitrary objects to data accessors and custom functions. 14 - Constant are no longer copied to each expression. 15 - Data accessors can now throw EvaluationExceptions. 16 - Removed dictionary interfaces. 17 - Switched from maven to gradle. 18 19 ## Author and License 20
··· 1 EvalEx - Java Expression Evaluator 2 ========== 3 4 + This is a personal fork of EvalEx with lots of incompatible and unstable changes. 5 6 Please check out the original repo here on [GitHub](https://github.com/ezylang/EvalEx). 7 8 Changes over upstream: 9 10 - Inlining of simple and constant expressions. 11 + - Lazy array and list conversions. 12 + - String multiplication and number conversion. 13 + ``` 14 + "Hello" * 3 => "HelloHelloHello" 15 + ``` 16 + - `DataAccessorIfc` data type. 17 - Immutable contexts and expressions. 18 - Replaced expression-wide variables with `evaluate` only parameters. 19 - `Object[]` in various places to allow passing arbitrary objects to data accessors and custom functions. 20 - Constant are no longer copied to each expression. 21 - Data accessors can now throw EvaluationExceptions. 22 + - Custom identifier characters. 23 - Removed dictionary interfaces. 24 - Switched from maven to gradle. 25 + - And more... 26 27 ## Author and License 28
+73
src/test/java/com/ezylang/evalex/ExpressionEvaluatorDataAccessorTest.java
···
··· 1 + package com.ezylang.evalex; 2 + 3 + import com.ezylang.evalex.data.DataAccessorIfc; 4 + import com.ezylang.evalex.data.EvaluationValue; 5 + import com.ezylang.evalex.data.types.DataAccessorValue; 6 + import com.ezylang.evalex.parser.ParseException; 7 + import org.assertj.core.api.Assertions; 8 + import org.junit.jupiter.api.Test; 9 + 10 + import java.lang.reflect.Field; 11 + import java.lang.reflect.Modifier; 12 + import java.math.BigDecimal; 13 + import java.util.HashMap; 14 + import java.util.HashSet; 15 + import java.util.Map; 16 + import java.util.Set; 17 + import java.util.function.Function; 18 + 19 + public class ExpressionEvaluatorDataAccessorTest extends BaseExpressionEvaluatorTest { 20 + 21 + @Test 22 + void testBasicAccessorAccess() throws ParseException, EvaluationException { 23 + DataAccessorValue value = DataAccessorValue.of(reflectiveAccessor(new TestClass())); 24 + 25 + Assertions.assertThat(createExpression("test_obj.testField") 26 + .evaluate(builder -> builder.parameter("test_obj", value))) 27 + .extracting(EvaluationValue::getBooleanValue).isEqualTo(true); 28 + 29 + Assertions.assertThat(createExpression("test_obj.testIntField") 30 + .evaluate(builder -> builder.parameter("test_obj", value))) 31 + .extracting(EvaluationValue::getNumberValue).isEqualTo(BigDecimal.valueOf(45)); 32 + 33 + Assertions.assertThat(createExpression("test_obj.coolString") 34 + .evaluate(builder -> builder.parameter("test_obj", value))) 35 + .extracting(EvaluationValue::getStringValue).isEqualTo("Hello World!"); 36 + 37 + Assertions.assertThatThrownBy(() -> createExpression("test_obj.noString") 38 + .evaluate(builder -> builder.parameter("test_obj", value))) 39 + .isInstanceOf(EvaluationException.class) 40 + .hasMessage("Field 'noString' not found in structure"); 41 + } 42 + 43 + public static class TestClass { 44 + public boolean testField = true; 45 + public int testIntField = 45; 46 + public final String coolString = "Hello World!"; 47 + } 48 + 49 + public static DataAccessorIfc reflectiveAccessor(Object object) { 50 + Map<String, Function<Object, Object>> fields = new HashMap<>(); 51 + Set<String> invalid = new HashSet<>(); 52 + return (variable, token, context) -> { 53 + if (fields.containsKey(variable)) return context.expression().convertValue(fields.get(variable).apply(object)); 54 + if (invalid.contains(variable)) return null; 55 + 56 + for (Field field : object.getClass().getFields()) { 57 + if (!field.getName().equals(variable)) continue; 58 + if (Modifier.isStatic(field.getModifiers())) continue; 59 + Function<Object, Object> function = object1 -> { 60 + try { 61 + return field.get(object1); 62 + } catch (IllegalAccessException e) { 63 + throw new RuntimeException(e); 64 + } 65 + }; 66 + fields.put(variable, function); 67 + return context.expression().convertValue(function.apply(object)); 68 + } 69 + invalid.add(variable); 70 + return null; 71 + }; 72 + } 73 + }