Panda.EL
What is EL?
EL = expression language. Panda.EL evaluate this expression and return it’s result.
Simple usage
System.out.println(EL.eval("3+4*5")); // Output: 23
Variable support
Map m = new HashMap();
m.put("a", 10);
System.out.println(EL.eval("a*10", m)); // Output: 100
The following java type variable are supported.
- int or Integer
- float or Float
- long or Long
- boolean or Boolean
- String
- T[] (Array)
- List
- Collection
- Map<?, ?>
- Java Object (POJO)
Supported operator
Operator | Operator Number | Priority | Description |
---|---|---|---|
() | * | 100 | Parenthesis |
, | * | 90 | Comma between parameter |
@ | 2 | 1 | Static method call |
. | 2 | 1 | Property or method accessor |
{1,2} | * | 1 | Java Array |
[‘abc’] | 2 | 1 | Object Property or Map Element |
[3] | 2 | 1 | Number indexed array/collection |
* | 2 | 3 | Multiply |
/ | 2 | 3 | Divide |
% | 2 | 3 | Mod |
+ | 2 | 4 | Plus |
- | 2 | 4 | Minus |
- | 2 | 2 | Negative |
>= | 2 | 6 | Great Equal |
<= | 2 | 5 | Less Equal |
== | 2 | 7 | Equal |
!= | 2 | 6 | Not Equal |
! | 2 | 7 | Not |
!! | 1 | 7 | Ignore exception and return null |
> | 2 | 6 | Greater |
< | 2 | 6 | Less |
&& | 2 | 11 | Logical And |
|| | 2 | 12 | Logical Or |
A|||B | 2 | 12 | Return B if A is empty or false, else return A |
?: | 2 | 13 | Ternary |
& | 2 | 8 | Bit AND |
~ | 2 | 2 | Bit NOT |
| | 2 | 10 | Bit OR |
^ | 2 | 9 | Bit XOR |
« | 2 | 5 | Bit Left Shift |
» | 2 | 5 | Bit Right Shift |
»> | 2 | 5 | Bit Right Shift (unsigned) |
Like Java
Panda.EL is completely faithful to Java basic arithmetic rules and does not do some extensions, such as the most common data type conversions.
In the process of numerical computation in Java, the type of the operation result is finally determined according to the type of both sides of the operator.
Example:
7/3 // return int
(1.0 * 7)/3 // return double
(1.0f * 7)/3 // return float
Method call
Example:
Map map = new HashMap();
map.put("a", new BigDecimal("7"));
map.put("b", new BigDecimal("3"));
assertEquals(10, EL.eval(map, "a.add(b).intValue()"));
Static method call
Example:
assertFalse((Boolean)EL.eval("'java.lang.Boolean'@FALSE"));
assertEquals(Boolean.TRUE, EL.eval("'java.lang.Boolean'@parseBoolean('true')"));
Some simple examples
General operation
System.out.println(EL.eval("3+2*5"));
// Output: 13
String manipulation
System.out.println(EL.eval("' abc '.trim()"));
// Output: abc
Java property
Map map = new HashMap();
Pet pet = new Pet();
pet.setName("GFW");
map.put("pet", pet);
System.out.println(EL.eval("pet.name", map));
// Output: GFW
Method call
Map map = new HashMap();
Pet pet = new Pet();
map.put("pet", pet);
EL.eval("pet.setName('XiaoBai')", map);
System.out.println(EL.eval("pet.getName()", map));
// Output: XiaoBai
Array element
Map map = new HashMap();
map.put("x", new String[] { "A", "B", "C" });
System.out.println(EL.eval("x[0].toLowerCase()"), map);
// Output: a
List
Map map = new HashMap();
map.put("x", Arrays.asList("A", "B", "C"));
System.out.println(EL.eval("x.get(0).toLowerCase()", map));
// Output: a
Map
Map map = new HashMap();
map.put("map", Jsons.toJson("{x:10, y:5}"));
System.out.println(EL.eval("map['x'] * map['y']", map));
// Output: 50
Logical
Map map = new HashMap();
map.put("a",5);
System.out.println(EL.eval("a>10", map));
// Output: false
map.put("a",20);
System.out.println(EL.eval("a>10", map));
// Output: true
Empty or exception handle
Map map = new HashMap();
map.set("obj", "pet");
ELContext ctx = new ELContext(map, true);
assertTrue((Boolean)EL.eval("!!(obj.pet.name) == null", ctx));
A or B
Map map = new HashMap();
map.set("obj", "pet");
assertEquals("cat", EL.eval("!!(obj.pet.name) ||| 'cat'", map));
strict mode
Defautly, EL use none strict mode (call method of null object will not raise exception)
Example:
Map map = new HashMap();
map.set("obj", "pet");
assertEquals("cat", EL.eval("obj.pet.name ||| 'cat'", map));
Run in strict mode will raise exception.
Example:
Map map = new HashMap();
map.set("obj", "pet");
ELContext ctx = new ELContext(map, true);
assertEquals("cat", EL.eval("!!(obj.pet.name) ||| 'cat'", map));
How about EL’s speed?
I think it’s not very fast. The principle of its work is such that each parse passes through 3 steps as below:
- Parse the expression to a suffix expression array
- Parse the suffix expression array into a operation tree
- Evaluate the root node of the operation tree
Of course, I also provide a method to improve efficiency, because if each evaluation passes through these 3 steps is certainly slow, we can precompile it first:
EL exp = new EL("a*10"); // Compile a expression and got a EL instance
Map m = new HashMap();
m.put("a", 10);
System.out.println(exp.eval(m)); // Output: 100
EL.eval() method is thread-safe.
Static call EL.eval(“xxx”) will lookup EL(“xxx”) from a internal WeakHashMap cache. if not found, will generate a EL(“xxx”) instance and save it to cache.