Package Documentation for org.apache.commons.jexl2 Package

Provides a framework for evaluating JEXL expressions.

- Introduction
- Brief Example
- Using JEXL
- Configuring JEXL
- Customizing JEXL

## Introduction

JEXL is a library intended to facilitate the implementation of dynamic and scripting features in applications and frameworks.

## A Brief Example

When evaluating expressions, JEXL merges an {@link org.apache.commons.jexl2.Expression} with a {@link org.apache.commons.jexl2.JexlContext}. An Expression is created using {@link org.apache.commons.jexl2.JexlEngine#createExpression(java.lang.String)}, passing a String containing valid JEXL syntax. A simple JexlContext can be created using a {@link org.apache.commons.jexl2.MapContext} instance; 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 a JexlEngine (could reuse one instead)
                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 jc = new MapContext();
                jc.set("foo", new Foo() );

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

## Using JEXL

The API is composed of three levels addressing different functional needs:

- Dynamic invocation of setters, getters, methods and constructors
- Script expressions known as JEXL expressions
- JSP/JSF like expression known as UnifiedJEXL expressions

### Important note

The only public packages you should use are:

- org.apache.commons.jexl2
- org.apache.commons.jexl2.introspection

The following packages follow a "use at your own maintenance cost" policy. Their classes and methods are not guaranteed to remain compatible in subsequent versions. If you think you need to use some of their features, it might be a good idea to check with the community through the mailing list first.

- org.apache.commons.jexl2.parser
- org.apache.commons.jexl2.scripting
- org.apache.commons.jexl2.internal
- org.apache.commons.jexl2.internal.introspection

### Dynamic invocation

These functionalities are close to the core level utilities found in BeanUtils. For basic dynamic property manipulations and method invocation, you can use the following set of methods:

- {@link org.apache.commons.jexl2.JexlEngine#newInstance}
- {@link org.apache.commons.jexl2.JexlEngine#setProperty}
- {@link org.apache.commons.jexl2.JexlEngine#getProperty}
- {@link org.apache.commons.jexl2.JexlEngine#invokeMethod}

The following example illustrate their usage:

                // test outer class
                public static class Froboz {
                    int value;
                    public Froboz(int v) { value = v; }
                    public void setValue(int v) { value = v; }
                    public int getValue() { return value; }
                }
                // test inner class
                public static class Quux {
                    String str;
                    Froboz froboz;
                    public Quux(String str, int fro) {
                        this.str = str;
                        froboz = new Froboz(fro);
                    }
                    public Froboz getFroboz() { return froboz; }
                    public void setFroboz(Froboz froboz) { this.froboz = froboz; }
                    public String getStr() { return str; }
                    public void setStr(String str) { this.str = str; }
                }
                // test API
                JexlEngine jexl = nex JexlEngine();
                Quux quux = jexl.newInstance(Quux.class, "xuuq", 100);
                jexl.setProperty(quux, "froboz.value", Integer.valueOf(100));
                Object o = jexl.getProperty(quux, "froboz.value");
                assertEquals("Result is not 100", new Integer(100), o);
                jexl.setProperty(quux, "['froboz'].value", Integer.valueOf(1000));
                o = jexl.getProperty(quux, "['froboz']['value']");
                assertEquals("Result is not 1000", new Integer(1000), o);

### JEXL script expression

If your needs require simple expression evaluation capabilities, the core JEXL features will most likely fit. The main methods are:

- {@link org.apache.commons.jexl2.JexlEngine#createExpression}
- {@link org.apache.commons.jexl2.JexlEngine#createScript}
- {@link org.apache.commons.jexl2.Expression#evaluate}

The following example illustrates their usage:

                JexlEngine jexl = nex JexlEngine();

                JexlContext jc = new MapContext();
                jc.set("quuxClass", quux.class);

                Expression create = jexl.createExpression("quux = new(quuxClass, 'xuuq', 100)");
                Expression assign = jexl.createExpression("quux.froboz.value = 10");
                Expression check = jexl.createExpression("quux[\"froboz\"].value");
                Quux quux = (Quux) create.evaluate(jc);
                Object o = assign.evaluate(jc);
                assertEquals("Result is not 10", new Integer(10), o);
                o = check.evaluate(jc);
                assertEquals("Result is not 10", new Integer(10), o);

### UnifiedJEXL script expressions

If you are looking for JSP-EL like and basic templating features, you can use UnifiedJEXL.

The main methods are:

- {@link org.apache.commons.jexl2.UnifiedJEXL#parse}
- {@link org.apache.commons.jexl2.UnifiedJEXL.Expression#evaluate}
- {@link org.apache.commons.jexl2.UnifiedJEXL.Expression#prepare}

The following example illustrates their usage:

                JexlEngine jexl = new JexlEngine();
                UnifiedJEXL ujexl = new UnifiedJEXL(jexl);
                UnifiedJEXL.Expression expr = ujexl.parse("Hello ${user}");
                String hello = expr.evaluate(context, expr).toString();

### Expressions Script and UnifiedJEXL.Expression: differences

#### Expression

This only allows for a single command to be executed and the result from that is returned. If you try to use multiple commands it ignores everything after the first semi-colon and just returns the result from the first command.

#### Script

This allows you to put multiple commands in the expression and you can use variable assignments, loops, calculations, etc. The result from the last command is returned from the script.

#### UnifiedJEXL.Expression

This is ideal to produce text. To get a calculation you use the EL-like syntax as in ${someVariable}. The expression that goes between the brackets behaves like a script, not an expression. You can use semi-colons to execute multiple commands and the result from the last command is returned from the script. You also have the ability to use a 2-pass evaluation using the #{someScript} syntax.

## JEXL Configuration

The JexlEngine can be configured through a few parameters that will drive how it reacts in case of errors. These configuration methods are best called at JEXL engine initialization time; it is recommended to derive from JexlEngine to call those in a constructor.

{@link org.apache.commons.jexl2.JexlEngine#setLenient} configures when JEXL considers 'null' as an error or not in various situations; when facing an unreferenceable variable, using null as an argument to an arithmetic operator or failing to call a method or constructor. The lenient mode is close to JEXL-1.1 behavior.

{@link org.apache.commons.jexl2.JexlEngine#setSilent} configures how JEXL reacts to errors; if silent, the engine will not throw exceptions but will warn through loggers and return null in case of errors. Note that when non-silent, JEXL throws JexlException which are unchecked exception.

{@link org.apache.commons.jexl2.JexlEngine#setDebug} makes stacktraces carried by JExlException more meaningfull; in particular, these traces will carry the exact caller location the Expression was created from.

{@link org.apache.commons.jexl2.JexlEngine#setClassLoader} indicates to a JexlEngine which class loader to use to solve a class name; this affects how JexlEngine.newInstance and the 'new' script method operates. This is mostly usefull in cases where you rely on JEXL to dynamically load and call plugins for your application.

JexlEngine and UnifiedJEXL expression caches can be configured as well. If you intend to use JEXL repeatedly in your application, these are worth configuring since expression parsing is quite heavy. Note that all caches created by JEXL are held through SoftReference; under high memory pressure, the GC will be able to reclaim those caches and JEXL will rebuild them if needed. By default, a JexlEngine does not create a cache whilst UnifiedJEXL does.

Both JexlEngine and UnifiedJEXL are thread-safe; the same instance can be shared between different threads and proper synchronization is enforced in critical areas.

{@link org.apache.commons.jexl2.JexlEngine#setCache} will set how many expressions can be simultaneously cached by the JEXL engine. UnifiedJEXL allows to define the cache size through its constructor.

{@link org.apache.commons.jexl2.JexlEngine#setFunctions} extends JEXL scripting by registering functions in namespaces.

This can be used as in:

                public static MyMath {
                    public double cos(double x) {
                        return Math.cos(x);
                    }
                }
                Map<String, Object> funcs = new HashMap<String, Object>();
                funcs.put("math", new MyMath());
                JexlEngine jexl = new JexlEngine();
                jexl.setFunctions(funcs);

                JexlContext jc = new MapContext();
                jc.set("pi", Math.PI);

                e = JEXL.createExpression("math:cos(pi)");
                o = e.evaluate(jc);
                assertEquals(Double.valueOf(-1),o);

If the namespace is a Class and that class declares a constructor that takes a JexlContext (or a class extending JexlContext), one namespace instance is created on first usage in an expression; this instance lifetime is limited to the expression evaluation.

## JEXL Customization

If you need to make JEXL treat some objects in a specialized manner or tweak how it reacts to some settings, you can derive most of its inner-workings.

{@link org.apache.commons.jexl2.JexlEngine} is meant to be extended and lets you capture your own configuration defaults wrt cache sizes and various flags. Implementing your own cache - instead of the basic LinkedHashMap based one - would be another possible extension.

{@link org.apache.commons.jexl2.JexlArithmetic} is the class to derive if you need to change how operators behave. For example, this would be the case if you wanted '+' to operate on arrays; you'd need to derive JexlArithmetic and implement your own version of Add.

{@link org.apache.commons.jexl2.Interpreter} is the class to derive if you need to add more features to the evaluation itself; for instance, you want pre- and post- resolvers for variables or nested scopes for for variable contexts or add factory based support to the 'new' operator.

{@link org.apache.commons.jexl2.introspection.UberspectImpl} is the class to derive if you need to add introspection or reflection capabilities for some objects. The code already reflects public fields as properties on top of Java-beans conventions.