Skip to end of metadata
Go to start of metadata


Compare with Current View Page History

« Previous Version 3 Next »

Janino as an Expression Evaluator

Say you build an e-commerce system, which computes the shipping cost for the items that the user put into his/her shopping cart. Because you don't know the merchant's shipping cost model at implementation time, you could implement a set of shipping cost models that come to mind (flat charge, by weight, by number of items, ...) and select one of those at run-time.

In practice, you will most certainly find that the shipping cost models you implemented will rarely match what the merchant wants, so you must add custom models, which are merchant-specific. If the merchant's model changes later, you must change your code, re-compile and re-distribute your software.

Because this is so unflexible, the shipping cost expression should be specified at run-time, not at compile-time. This implies that the expression must be scanned, parsed and evaluated at run-time, which is why you need an expression evaluator.

A simple expression evaluator would parse an expression and create a "syntax tree". The expression "a + b * c", for example, would compile into a "Sum" object who's first operand is parameter "a" and who's second operand is a "Product" object who's operands are parameters "b" and "c". Such a syntax tree can evaluated relatively quickly. However, the run-time performance is about a factor of 100 worse than that of "native" JavaTM code executed directly by the JVM. This limits the use of such an expression evaluator to simple applications.

Also, you may want not only do simple arithmetics like "a + b * c % d", but take the concept further and have a real "scripting" language which adds flexibility to your application. Since you know the JavaTM programming language already, you may want to have a syntax that is similar to that of the JavaTM programming language.

All these considerations lead to compilation of JavaTM code at run-time, like some engines (e.g. JSP engines) already do. However, compiling JavaTM programs with SUN's JDK is a relatively resource-intensive process (disk access, CPU time, ...). This is where Janino comes into play... a light-weight, "embedded" JavaTM compiler that compiles simple programs in memory into JavaTM bytecode which executes within the JVM of the running program.

OK, now you are curious... this is how you use the ExpressionEvaluator:

Notice: If you pass a string literal as the expression, be sure to escape all JavaTM special characters, especially backslashes.

Compilation of the expression takes 670 microseconds on my machine (2 GHz P4), evaluation 0.35 microseconds (approx. 2000 times faster than compilation).

There is a sample program "ExpressionDemo" that you can use to play around with the ExpressionEvaluator, or you can study ExpressionDemo's source code to learn about ExpressionEvaluator's API:

Janino as a Script Evaluator

Analogously to the expression evaluator, a ScriptEvaluator API exists that compiles and processes a JavaTM "block", i.e. the body of a method. If a return value other than "void" is defined, then the block must return a value of that type. Example:

As for the expression compiler, there is a demo program "ScriptDemo" for you to play with the ScriptEvaluator API:

Check the source code of ScriptDemo to learn more about the ScriptEvaluator API.

Janino as a Class Body Evaluator

Analogously to the expression evaluator and the script evaluator, a ClassBodyEvaluator exists that compiles and processes the body of a JavaTM class, i.e. a series of method and variable declarations. If you define a contract that the class body should define a method named "main()", then your script will look almost like a "C" program:

The "ClassBodyDemo" program (source code) demonstrates this:

Janino as a Simple Compiler

The SimpleCompiler compiles a single "compilation unit" (a.k.a. ".java" file). Opposed to to normal JavaTM compilation, that compilation unit may define more than one public class. Example:

It returns a ClassLoader from which you can retrieve the classes that were compiled.

  • No labels