Mastering Aviator: A High‑Performance Java Expression Engine for Backend Development
Aviator is a lightweight, high‑performance Java expression evaluation engine that compiles expressions to JVM bytecode, offering rich operator support, custom functions, variable handling, and compilation for reuse, while detailing its features, limitations, dependency setup, and multiple code examples for practical backend integration.
Aviator Introduction
Aviator is a high‑performance, lightweight Java expression evaluation engine designed for dynamic evaluation of various expressions. Compared with heavyweight scripting languages like Groovy or JRuby, Aviator is small (≈450 KB with dependencies, ≈70 KB without) and its syntax is a limited subset of a full language.
Unlike many evaluators that interpret expressions, Aviator compiles them directly to Java bytecode, positioning it between heavyweight script languages and ultra‑lightweight engines.
Aviator Features
Supports most operators: arithmetic, relational, logical, bitwise, regex (=~), ternary (?:) with proper precedence and parentheses.
Function calls and custom functions.
Built‑in regex matching with Ruby/Perl‑style syntax and $digit group references.
Automatic type conversion; operations convert operands as needed, throwing an exception if conversion fails.
Variable injection with nested access (e.g., a.b.c).
Functional‑style
seqlibrary for collections and arrays.
Aviator Limitations
No control‑flow statements such as
if,
else,
do/while; only logical, arithmetic, ternary, and regex expressions are allowed.
Octal literals are not supported; only decimal and hexadecimal literals are allowed.
Overall Structure
Aviator’s architecture is simple, following the typical evaluator design.
Usage Examples
Dependencies
<code><dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</code>Example 1: Simple addition
<code>public class SimpleExample {
public static void main(String[] args) {
Long result = (Long) AviatorEvaluator.execute("1+2+3");
System.out.println(result);
}
}
</code>The result is a
Long, because Aviator only supports
Longand
Doublenumeric types.
Example 2: Passing parameters
<code>public class InputParamsExample {
public static void main(String[] args) {
Map<String, Object> env = new HashMap<>();
env.put("name", "张三");
String result = (String) AviatorEvaluator.execute("'你的姓名是' + name", env);
System.out.println(result);
}
}
</code>Output: 你的姓名是张三。
Example 3: exec method (Aviator 2.2+)
<code>public class ExecParamsExample {
public static void main(String[] args) {
String myname = "dennis";
Object result = AviatorEvaluator.exec("'hello ' + name", myname);
System.out.println(result);
}
}
</code>Example 4: Function calls (Lua‑like syntax)
<code>public class InvokeFunctionExample {
public static void main(String[] args) {
Object res1 = AviatorEvaluator.execute("string.length('hello')");
Object res2 = AviatorEvaluator.execute("string.substring('hello',1,2)");
Object res3 = AviatorEvaluator.execute("string.contains('hello','ll')");
Object res4 = AviatorEvaluator.exec("string.length(name)", "我是中国人");
System.out.println(res1 + "\t" + res2 + "\t" + res3 + "\t" + res4);
}
}
</code>Example 5: Custom function
Implement
com.googlecode.aviator.runtime.type.AviatorFunction(or extend
AbstractFunction) and register it.
<code>public class AddFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
Number left = FunctionUtils.getNumberValue(arg1, env);
Number right = FunctionUtils.getNumberValue(arg2, env);
return new AviatorDouble(left.doubleValue() + right.doubleValue());
}
public String getName() {
return "add";
}
}
</code> <code>public class CustomFunctionExample {
public static void main(String[] args) {
AviatorEvaluator.addFunction(new AddFunction());
System.out.println(AviatorEvaluator.execute("add(10,100)"));
}
}
</code>Example 6: Compile expression
<code>public class CompileExample {
public static void main(String[] args) {
String expression = "a-(b-c) > 100";
Expression compiledExp = AviatorEvaluator.compile(expression);
Map<String, Object> env = new HashMap<>();
env.put("a", 100.3d);
env.put("b", 45);
env.put("c", -199.100d);
Boolean result = (Boolean) compiledExp.execute(env);
System.out.println(result);
}
}
</code>Compiled expressions can be reused with different environments, improving performance. The engine supports comparison operators for numbers, strings, patterns, booleans, and any objects implementing
java.lang.Comparable.
Example 7: Access arrays and collections
<code>public class CollectionExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("我是");
list.add("中国人");
int[] array = new int[3];
array[0] = 10;
array[1] = 100;
array[2] = 1000;
Map<String, Object> map = new HashMap<>();
map.put("date", LocalDate.now());
Map<String, Object> env = new HashMap<>();
env.put("list", list);
env.put("array", array);
env.put("mmap", map);
System.out.println(AviatorEvaluator.execute(
"list[0]+list[1]+'\narray[0]+array[1]+array[2]='+ (array[0]+array[1]+array[2]) +' \ntoday is '+ mmap.date",
env));
}
}
</code>The next article will cover ternary operators, regex matching, date comparison, big‑number calculations, and precision.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.