 |
EL Comparisons
Posted by jhook on November 16, 2006 at 12:28 PM | Comments (12)
Updated 11/17/2006 with JEXL and upgraded MVEL and added Serialized size
I decided to test the following EL libraries available today:
- Commons EL (http://jakarta.apache.org/commons/el/)
Implementation of the JSP EL API that's existed forever. This library can be found in many JSP containers (Tomcat for example) or used as a foundation for within many vendor's J2EE servers.
- OGNL (http://www.ognl.org/)
One of the most expressive ELs available today and widely used with WebWork (Struts 2) and Tapestry.
- MVEL (http://wiki.mvflex.org/index.php?title=MVFLEX_Expression_Language)
A newcomer to EL which is part of the MVFlex/Valhalla project. Features look more in line with OGNL's offering with method invocation and some interesting regular expression support.
- EL-API (http://jcp.org/en/jsr/detail?id=245)
Sun's reference implementation of the new EL-API which is part of JEE 5 and available with Glassfish. Syntax features are basically the same as the EL from JSP, but with additinal API features.
- JEXL (http://jakarta.apache.org/commons/jexl/)
An implementation based on Velocity's parser. Because of this, it acts more like a limited templating solution with things like method invocation.
Here's a table of features I thought were pertinent:
| Library |
A.B Accessors |
Math |
Method Invocation |
Projections |
Regular Expressions |
Coercion |
Conversion |
Pluggable Property Resolution |
Pluggable Method Resolution |
Serializable |
Factory Caching |
| Commons-EL |
Yes |
Yes |
No (functions) |
No |
No |
Yes |
No |
No |
No |
No |
Yes |
| OGNL |
Yes |
Yes |
Yes |
Yes |
No |
Yes |
Yes |
Yes |
Yes |
Yes |
No |
| MVEL |
Yes |
Yes |
Yes |
No |
Yes |
Yes |
No |
No |
No |
? |
No |
| EL-RI |
Yes |
Yes |
No (functions) |
No |
No |
Yes |
No |
Yes |
No |
Yes |
Yes |
| JEXL |
Yes |
Yes |
Yes |
No |
No |
Yes |
No |
No |
No |
No |
No |
Pretty obvious things that stand out are that OGNL and MVEL have a lot more syntax features compared to the standardized EL. I think this is largely impart to the fact that EL was only intended for simple notation within the View counterparts and not as a scripting language. I will say that there's absolutely no reason why these other syntax features shouldn't be added to future releases.
Pertaining to pluggability of syntax evaluation, OGNL is the most expressive with Method, Property, Index, etc. The new EL-API has similar capabilities for Property and Index Accessors with chainable ELResolvers.
*Factory Cached means the API's factory method inherently cache expressions to some degree and do not re-parse on every call.
API Use:
Commons-EL
ExpressionFactory fact = new ExpressionFactoryImpl();
VariableResolver vars = new VariableResolverImpl(..);
Expression expr = fact.parseExpression(str, Object.class, null);
Object value = expr.evaluate(vars);
OGNL
Map vars = new HashMap();
Object expr = Ognl.parseExpression(str);
Object valu = Ognl.getValue(expr, vars);
MVEL
Map vars = new HashMap();
Object value = Interpreter.eval(str, vars);
EL-RI
ExpressionFactory fact = new ExpressionFactoryImpl();
ELContext ctx = new ELContext(...);
ValueExpression ve = fact.createValueExpression(ctx, str);
Object value = ve.getValue(ctx);
JEXL
Expression e = ExpressionFactory.createExpression( jexlExp );
JexlContext jc = JexlHelper.createContext();
Object value = e.evaluate(jc);
Finally, I have some performance numbers at 10,000 iteration, average time in milliseconds:
| Library |
test.fubar != null |
test.num + 10 - 1 |
| Commons-EL |
0.00249 |
0.00343 |
| OGNL |
0.20751 |
0.23535 |
| MVEL |
0.02032 |
0.03775 |
| EL-RI |
0.00714 |
0.00715 |
| JEXL |
0.34199 |
0.21907 |
| Commons-EL (re-use) |
0.00597 |
0.01462 |
| OGNL (re-use) |
0.00342 |
0.00712 |
| EL-RI (re-use) |
0.00394 |
0.00767 |
| JEXL (re-use) |
0.04946 |
0.01123 |
*re-use means take the Expression returned from the factory and keep evaluating that instance instead of going back to the factory again. This didn't show much of a difference for those EL libraries that cache within their factories, but it did show a big improvement with OGNL and JEXL.
Serialization can be important for some libraries and the EL-RI was optimized for use with JSF's state-saving architecture. I'm sure other frameworks may have similar concerns. Here are the sizes in bytes for the couple libraries that were actually Serializable.
| Library |
test.fubar != null |
test.num + 10 - 1 |
| OGNL |
594 |
764 |
| EL-RI |
170 |
169 |
Synchronization was another thing I wanted to test, but haven't yet. Supposedly OGNL has some unwanted synchronization blocks and JEXL has not been optimized at the Factory level at all-- putting a synchronization block around expression creation, with calls to commons-logging.
In summary, here's just my observations from an afternoon of testing. While I'm not an expert on all of the libraries listed, feel free to comment on where I might have missed a point or gotten things wrong.
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
You say MVEL has No regex support in your chart, which is not correct. But I see that's a mistake, since you acknowledge that in your description.
Note: By using the Interpreter in MVEL (which is a template parser, there is more overhead.) It might be more fair to test MVEL with the ExpressionParser.eval(ex, vars) method.
Posted by: cbrock on November 16, 2006 at 02:32 PM
-
I should also say that MVEL 1.1 will support pre-compiling and caching, which will yield a big improvement in the performance.
Posted by: cbrock on November 16, 2006 at 02:34 PM
-
Yeah, I put in the RegExp and mentioned it as a plus for MVEL, but mistakenly marked it in the table. When the new version is released, I can run another comparison, adding a (re-use) entry for MVEL.
Posted by: jhook on November 16, 2006 at 02:36 PM
-
Any experience with JXPath?
Posted by: dwalend on November 16, 2006 at 04:06 PM
-
Alright, I've posted the 1.1 beta on the MVEL website, which implements the aforementioned caching.
But I highly suggest (for all fairness with the comparisons) that you base your benchmark on the ExpressionParser.eval() methods, not the Interpreter.
Posted by: cbrock on November 16, 2006 at 04:13 PM
-
Wicket also implement a OGNL like EL, it is
wicket.util.lang.PropertyResolver
Posted by: fugui on November 16, 2006 at 07:58 PM
-
Can you be more specific about the expression that you timed?
Posted by: varan on November 16, 2006 at 10:20 PM
-
Pertaining to MVEL-- I looked at ExpressionParser.eval(...), but it didn't accept the "@{...}" notation. I didn't think it was appropriate to remove this in account that Commons-EL and the EL-RI both support this higher level templating. Sending ExpressionParser the base String didn't actually evaluate anything and returned null-- not sure what was going on.
Posted by: jhook on November 16, 2006 at 10:44 PM
-
varan-- the expressions I used were fairly simple, but common cases from another site. They are listed in the header. The tests were run 3 times to allow the JVM to warm up and the the tests were run in parallel (each of the 100,000 iterations, time each library).
Posted by: jhook on November 16, 2006 at 10:46 PM
-
You've got me obsessed with optimization now. MVEL 1.1beta2 is out with a more streamlined template processor.
Posted by: cbrock on November 17, 2006 at 09:37 AM
-
I have released MVEL 1.1beta3 which now fully implements expression pre-compiling (but only through the ExpressionParser).
However, the Interpreter factory methods can be coerced to pre-compile and reuse subexpressions through the new factory setting: Interpreter.setCacheAggressively(true);
Try downloading beta3 and putting the Interpreter into aggressive cache mode and re-run your tests. :P
Posted by: cbrock on November 17, 2006 at 03:27 PM
-
I should note that cache aggressively does NOT cache any output values, it simply forces the template parser to pre-compile and re-use compiled expression trees internally using a weakly-referenced cache.
Posted by: cbrock on November 17, 2006 at 03:31 PM
|