QLExpress 4: Alibaba's Java Expression Engine for Business Rules
QLExpress is a powerful, lightweight, dynamic language for the Java platform aimed at improving developers’ productivity in different business scenes.
At a glance
- What is it?
- QLExpress 4 is an Antlr4-based rewrite of Alibaba's embedded Java scripting engine, with expression tracing, native JSON literals and function values. It suits teams that let non-developers configure rules; it does not sandbox untrusted code by default.
- Who is it for?
- Adopt QLExpress 4 if you are on JDK 8 or later and need a small Java dependency that lets operations staff or product managers own rule expressions, with tracing available for post-hoc attribution. Do not adopt it as a sandbox for code you did not write: the README states scripts are blocked from interacting with application code by default, and the open security strategy in the documented examples switches that protection off.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 45 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
Why Alibaba built a second expression engine instead of reusing the first
QLExpress grew out of Alibaba's e-commerce rule configuration and was open sourced in 2012. The README describes version 4 not as a refactor of that engine but as a rewrite of the parsing layer on Antlr4, with the older line kept alive on a branch named branch_version_3.x.x. That split is the first thing to understand, because it means the two versions do not share a grammar and the 3.x documentation does not describe 4.x behaviour.
The problem it addresses is concrete. A coupon rule, a form-builder dependency between two dragged controls, a process-engine condition, an ad billing formula: these are all small boolean or arithmetic expressions that a business user wants to change without a release. Embedding a general-purpose JVM language for that job is too much surface area. Writing a bespoke parser is worse. QLExpress sits between the two: a Java-hosted expression language with a C-like syntax, extension points for custom functions and operators, and a JSON literal syntax for describing data structures inline. The audience is Java teams whose rule authors are not necessarily Java developers, and who want the rules to live as text rather than as compiled classes.
How QLExpress 4 executes a script and where the values come from
The entry point is Express4Runner. You construct it with an InitOptions object, then call execute with three things: the script text, a Map context, and a QLOptions object. The context map is the variable namespace. A key of "a" in the map is the identifier a inside the script. The QLOptions object carries per-execution settings, including attachments, and the call returns a QLResult whose getResult() gives the computed value.
The README's own example computes a + b * c with a, b and c bound to 1, 2 and 3 and asserts the result is 7, which confirms the engine applies ordinary arithmetic precedence rather than left-to-right evaluation.
Extensions attach to the runner, not to the script. addVarArgsFunction registers a function that receives all arguments, and addOperatorBiFunction registers an infix operator taking a left and a right operand. Both accept Java lambdas, so a function is a few lines of Java rather than a class. When the logic needs execution context, you implement CustomFunction instead and receive a QContext and a Parameters object in the call method.
The security model is worth stating precisely. The README says scripts are by default not permitted to interact with application code. The examples that register functions defined inside a script pass InitOptions.builder().securityStrategy(QLSecurityStrategy.open()), which is the explicit opt-out. Attachments exist for the opposite reason: tenant names, passwords and similar values can be handed to a custom function through QLOptions.attachments without ever becoming script-visible variables.
Installing qlexpress4 and running your first expression
The artifact is published under groupId com.alibaba as qlexpress4, and the README lists version 4.1.3 as the current one. JDK 8 or higher is the stated requirement, which is unusual for a project rewritten in 2026 and is a deliberate compatibility choice rather than an oversight.
Add the dependency to your Maven build:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>qlexpress4</artifactId>
<version>4.1.3</version>
</dependency>The smallest working program builds a runner, fills a context map and executes a string. This is the README's first example, and the assertion is the one it ships with:
Express4Runner express4Runner = new Express4Runner(InitOptions.DEFAULT_OPTIONS);
Map<String, Object> context = new HashMap<>();
context.put("a", 1);
context.put("b", 2);
context.put("c", 3);
Object result = express4Runner.execute("a + b * c", context, QLOptions.DEFAULT_OPTIONS).getResult();
assertEquals(7, result);If it runs, result holds the integer 7. Registering a custom function is one more call before execute:
express4Runner.addVarArgsFunction("join",
params -> Arrays.stream(params).map(Object::toString).collect(Collectors.joining(",")));
Object resultFunction =
express4Runner.execute("join(1,2,3)", Collections.emptyMap(), QLOptions.DEFAULT_OPTIONS).getResult();
assertEquals("1,2,3", resultFunction);The same name can also be registered as an infix operator, so that 1 join 2 join 3 produces the same string. That dual registration is the mechanism behind the README's claim that you can build a domain-specific rule dialect quickly, and it is the part worth prototyping first, because operator precedence for a custom infix operator is the kind of detail that only shows up once your rule authors start writing real expressions.
Expression tracing is the feature that separates QLExpress 4 from a plain evaluator
Most expression engines return one value and discard the intermediate ones. QLExpress 4 keeps them. The README describes tracing as the ability to obtain the value of every intermediate node during evaluation, and frames the use case as attribution: given a rule such as isVip && not logged in for more than 10 days, a rule platform wants to know how many users were stopped by the VIP clause and how many by the login clause. With two conditions that is a nice-to-have; with a rule that has been edited by three people over a year, it is the only practical way to explain why production behaves the way it does.
The README states that a rule platform built on this capability performs attribution analysis and annotation over live rules, and that the accumulated data feeds later rule tuning. That is a real architectural commitment: it means traced executions produce more than a boolean, so you should expect to store and query the trace output, not just the result. The README does not document the trace payload's size or retention characteristics, so that is something to measure against your own rule shapes before you enable it everywhere.
This is also the feature most likely to be absent from alternatives. If explaining a rule's outcome to a non-engineer is a requirement rather than a nice-to-have, it narrows the field considerably.
JSON literals, interpolated strings and the semicolon question
Three smaller language decisions are worth knowing before you write a style guide for rule authors. First, JSON syntax is native: a JSON array in a script is a List and a JSON object is a Map, and the README points to model-to-model mapping as the product pattern this enables. Second, strings can embed expressions directly using the ${expression} form, which removes most of the concatenation noise from generated messages. Third, semicolons can be omitted.
That last one is a genuine fork in the road. Omitting semicolons makes short expressions cleaner and makes long scripts harder to scan, and the README leaves the choice to the author rather than imposing one. If several people edit the same rules, pick a convention and enforce it outside the engine, because the language will not do it for you.
Function values are the other change worth flagging. In version 4 a function is a first-class value: it can be assigned to a variable and returned from another function. The README's example assigns a lambda to add and then calls add(1,2). Functions can also be combined with Java's Stream-style APIs, and the README lists Lambda expressions, list filter and map, Stream API and functional interfaces as separate topics. For a rule engine, first-class functions mainly mean that reusable rule fragments can be composed rather than copy-pasted.
Where QLExpress 4 is the wrong choice
The default-deny security posture is a starting point, not a guarantee. The README describes scripts as blocked from interacting with application code unless you define a safe interaction yourself, and the examples that add script-defined functions explicitly switch to QLSecurityStrategy.open(). That strategy name is the honest signal: once you open it, you are trusting the script author. If your rule authors are end users on a multi-tenant platform, the security strategy is a design decision you have to make and test, not a checkbox.
A second boundary is the execution model. QLExpress 4 interprets; it does not compile to bytecode, and the README presents that as an advantage because interpretation does not consume JVM metaspace. The trade-off is that a caching layer is the documented way to improve interpretation performance, which means throughput depends on how well your rule set caches rather than on the engine alone. The README does not publish benchmark numbers, so any performance expectation has to come from your own workload.
Third, the project is not a workflow engine, a decision table or a rules management UI. It evaluates expressions and returns values. The README's product screenshots are of rule platforms built on top of it, not of features it ships. If you need a visual rule editor, you are building it.
Finally, the version split matters for existing users. Version 4 rewrote the parser on Antlr4, and the README directs 3.x users to a maintenance branch and to an upgrade guide rather than promising drop-in compatibility. Treat the move from 3.x to 4.x as a migration with its own test pass.
QLExpress 4 against AviatorScript
AviatorScript is the comparison the search data keeps returning, and the two take different positions on the same problem. AviatorScript is a general-purpose JVM scripting language: you write scripts that are programs, with their own control flow and semantics, and the engine compiles them for speed. QLExpress 4 is narrower by design. Its grammar is deliberately close to Java and C so that Java developers and C-like-language business users can read a rule without learning a new language, and its extension points are oriented toward embedding a domain dialect rather than writing standalone scripts.
The practical difference shows up in two places. QLExpress 4 ships expression tracing, which AviatorScript does not offer as a documented capability, and that is the reason to pick it if attribution analysis is on your roadmap. AviatorScript's compilation model is the reason to pick it if raw script throughput dominates and you can accept a language your rule authors must learn separately. Neither is a superset of the other, and the choice is really about whether your rules are expressions embedded in a Java application or scripts that stand on their own.
Licence, maintenance and what an upgrade costs
QLExpress is licensed under Apache-2.0, which permits commercial and closed-source use and requires that you retain the licence and attribution notices. This is a description of the licence text, not legal advice; if you redistribute the library inside a product, have your own counsel confirm the notice obligations.
The repository is not archived, and the most recent push recorded is 2026-08-15, the same date as the v4.1.3 release. The release cadence visible in the release list is roughly quarterly: 4.1.1 in May 2026, 4.1.2 in June 2026 (marked deprecated), and 4.1.3 in August 2026. The upgrade cost is the part to plan for. A parser rewrite on Antlr4 means the 3.x grammar and the 4.x grammar are different implementations, and the README routes 3.x users to a maintenance branch and an upgrade guide rather than describing 4.x as a drop-in replacement. Budget for a rule-by-rule test pass, and note that the deprecated 4.1.2 should be skipped in favour of 4.1.3.
Editorial conclusion
Adopt QLExpress 4 if you are on JDK 8 or later and need a small Java dependency that lets operations staff or product managers own rule expressions, with tracing available for post-hoc attribution. Do not adopt it as a sandbox for code you did not write: the README states scripts are blocked from interacting with application code by default, and the open security strategy in the documented examples switches that protection off. Before committing, verify the security strategy you intend to run under, and check the 3.x upgrade guide if you are migrating an existing rule set, because the parser was rewritten on Antlr4 and the 3.x line lives on a separate maintenance branch.
Frequently asked questions
What is QLExpress 4 and what is it used for?
It is an embedded dynamic expression language for the Java platform, derived from Alibaba's e-commerce rule configuration and open sourced in 2012. The README lists coupon rule configuration, form-builder control dependencies, process engine conditions and ad billing rules as typical uses.
How do I add QLExpress 4 to a Maven project?
Add the dependency with groupId com.alibaba, artifactId qlexpress4 and the version shown in the README, then construct an Express4Runner with InitOptions.DEFAULT_OPTIONS. JDK 8 or higher is required.
Is QLExpress 4 safe to run scripts written by end users?
The README states that scripts are not allowed to interact with application code by default, and that you can define a safe interaction method yourself. The documented examples that add script-defined functions pass QLSecurityStrategy.open(), which removes that default restriction, so the security strategy is a deliberate choice.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/alibaba-qlexpress)
Community notes