3 method to evaluate expressions in Java

August 7, 2011 by
Filed under: java 

The problem: You need to evaluate dynamic expression in your java code. Some common situation includes on a program contest evaluation system, on a dynamic business logic control,  on evaluation of dynamic math expression, or even on evaluation of test case.

There is many ways evaluate expression. These methods can be categorized into 3 different ways generally.

Method 1. Leverage dynamic compilation in Java.

You can add the dynamic expressions to codes of a skeleton class  template; and then compile the class.  It is the most original and flexible way to evaluate expressions. For full instructions see my last post:

3 steps to dynamically compile, instantiate and run a Java class.

Method 2. Evaluate expressions by java libraries.

There’s dozens of libraries to evaluate expression in java. The most intuitive and powerful library should be jexl and expressionoasis.

http://commons.apache.org/jexl/

http://code.google.com/p/expressionoasis/

When evaluating expressions, JEXL merges an Expression with a JexlContext. An Expression is created using JexlEngine#createExpression(), passing a String containing valid JEXL syntax. A simple JexlContext can be created by instantiating a MapContext; a map of variables that will be internally wrapped can be optionally provided through its constructor. The following example, takes a variable named foo, and invokes the bar() method on the property innerFoo:

// Create or retrieve a JexlEngine
JexlEngine jexl = new JexlEngine();
// Create an expression object
String jexlExp = "foo.innerFoo.bar()";
Expression e = jexl.createExpression( jexlExp );

// Create a context and add data
JexlContext jctx = new MapContext();
jctx.set("foo", new Foo() );

// Now evaluate the expression, getting the result
Object o = e.evaluate(jctx);

Method 3. Evaluate expression by scripting engine

You can evaluate expression in your java code by scripting engine supported by Java platform. You are free to script the expressions in your favorite language.  To show all available scripting engines in your system:

    private static void availableEngine()
    {
        ScriptEngineManager mgr = new ScriptEngineManager();
        List<ScriptEngineFactory> factories = mgr.getEngineFactories();
        for (ScriptEngineFactory factory : factories)
        {
            System.out.println("ScriptEngineFactory Info");
            String engName = factory.getEngineName();
            String engVersion = factory.getEngineVersion();
            String langName = factory.getLanguageName();
            String langVersion = factory.getLanguageVersion();
            System.out.printf("\tScript Engine: %s (%s)\n", engName, engVersion);
            List<String> engNames = factory.getNames();
            for (String name : engNames)
            {
                System.out.printf("\tEngine Alias: %s\n", name);
            }
            System.out.printf("\tLanguage: %s (%s)\n", langName, langVersion);
        }
    }

By default, JavaScript engine is included in JVM. So you can write expression in javascript with java variable support, and evaluate it in java code. Example code:

    private static void jsEvalWithVariable()
    {
        List<String> namesList = new ArrayList<String>();
        namesList.add("Jill");
        namesList.add("Bob");
        namesList.add("Laureen");
        namesList.add("Ed");

        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");

        jsEngine.put("namesListKey", namesList);
        System.out.println("Executing in script environment...");
        try
        {
          jsEngine.eval("var x;" +
                        "var names = namesListKey.toArray();" +
                        "for(x in names) {" +
                        "  println(names[x]);" +
                        "}" +
                        "namesListKey.add(\"Dana\");");
        }
        catch (ScriptException ex)
        {
            ex.printStackTrace();
        }
    }

You can also script in groovy, ruby, python… Groovy can be well integrated with jvm, let’s take groovy as an example.  Firstly include groovy 1.7.10 in pom file if you’re using maven ( or include groovy engine jar groovy-engine.jar in the classpath of the project if not using maven).

  <dependency>
  	<groupId>org.codehaus.groovy</groupId>
  	<artifactId>groovy</artifactId>
  	<version>1.7.10</version>
  </dependency>

Secondly write scripts in groovy, and finally evaluate them by ScriptEngine.

It is a common practice to access java variables and objects in you expressions only if you binds the variables/objects to your script engine object. You can evaluate expression in your groovy engine like this:

    private static class Position
    {
        private int x;
        private int y;
        public Position(int x, int y)
        {
            super();
            this.x = x;
            this.y = y;
        }

    }

    //require(jar:'groovy-engine.jar')
    // or include any version of groovy 1.7.10 or above in your pom file
    private static void groovyEval()
    {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("groovy");

        if(null==engine)
        {
            System.err.println("Could not find groovy script engine,make sure to include groovy engine in your classpath");
        }
        try
        {
            // basic groovy expression example
            System.out.println(engine.eval("(1..10).sum()"));

            // example showing scripting with variables (object method invoking)
            engine.put("first", "HELLO");
            engine.put("second", "world");
            System.out.println(engine.eval("first.toLowerCase() + second.toUpperCase()"));

            //example with boolean expression
            engine.put("m", 3);
            engine.put("n", 9);
            System.out.println(engine.eval("m<n"));

            //example with variable object and object member access:
            Position pos = new Position(100, 200);
            engine.put("p", pos);
            System.out.println(engine.eval("p.y-p.x>0"));
        }
        catch (ScriptException e)
        {
            e.printStackTrace();
        }
    }

Finally, if you just want to evaluate and debug complicated math expression, Math Expression Evaluator may help:

http://www.beyondlinux.com/blog/handy-utilities/math-expression-calculator/

 

Digg This
Reddit This
Stumble Now!
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Comments

Comments are closed.