Exploring Spring Boot’s Seven Expression Engines – Part 2
This article introduces four of Spring Boot’s expression engines—Groovy, MVEL, JEXL, and JSP EL—showing how to add their Maven dependencies, run concrete code examples, and provides practical guidance on selecting the right engine based on performance, feature richness, and integration ease.
Groovy
Groovy is a dynamic JVM language with Java‑compatible syntax, supporting closures, metaprogramming, and collection operations. In Spring Boot it can be used via GroovyScriptEngine or GroovyShell to evaluate scripts at runtime.
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>4.0.21</version>
</dependency>
<!-- or use groovy‑jsr223 -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-jsr223</artifactId>
<version>4.0.21</version>
</dependency>Basic JSR‑223 usage:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.HashMap;
import java.util.Map;
public class GroovyExpressionExample {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
// Simple expression
Object result = engine.eval("3 * 4 + 2");
System.out.println(result); // 14
// Expression with parameters
String expr = "(a > 2 || b > 2) && (c > 2 || d > 10)";
String script = "def evaluate() { return " + expr + " }";
engine.eval(script);
Map<String, Object> params = new HashMap<>();
params.put("a", 1);
params.put("b", 1);
params.put("c", 1);
params.put("d", 1);
params.forEach(engine::put);
if (engine instanceof javax.script.Invocable) {
javax.script.Invocable inv = (javax.script.Invocable) engine;
Boolean r = (Boolean) inv.invokeFunction("evaluate");
System.out.println(r); // false
}
// Direct variable usage
engine.put("x", 10);
engine.put("y", 5);
System.out.println(engine.eval("x * y - 3")); // 47
}
}Utility component for Spring Boot integration:
import org.springframework.stereotype.Component;
import javax.script.*;
import java.util.Map;
@Component
public class GroovyScriptUtils {
private static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("groovy");
public static Object evaluateExpression(String expression, Map<String, Object> params) throws ScriptException {
Bindings bindings = ENGINE.createBindings();
bindings.putAll(params);
return ENGINE.eval(expression, bindings);
}
}MVEL
MVEL blends dynamic and static features, offering concise syntax and high performance. It is used in rule engines (e.g., Drools) and template rendering, supporting property navigation, collection projection/selection, assignment, flow control, and direct Java class/method access. It can be interpreted or compiled to bytecode.
<dependency>
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.4.17.Final</version>
</dependency>Example:
import org.mvel2.MVEL;
import java.util.HashMap;
import java.util.Map;
public class MVELExample {
public static void main(String[] args) {
// Compile and execute simple expression
String expr = "a * b + c";
Map<String, Object> params = new HashMap<>();
params.put("a", 5);
params.put("b", 3);
params.put("c", 2);
Object compiled = MVEL.compileExpression(expr);
Integer result = (Integer) MVEL.executeExpression(compiled, params);
System.out.println(result); // 17
// Interpreted execution
System.out.println((Integer) MVEL.eval(expr, params)); // 17
// Collection projection
Map<String, Object> data = new HashMap<>();
data.put("users", java.util.Arrays.asList(
new User("John", 30),
new User("Jane", 25),
new User("Bob", 40)));
Object names = MVEL.eval("users.{name}", data);
System.out.println(names); // [John, Jane, Bob]
// Conditional expression
Map<String, Object> person = new HashMap<>();
person.put("age", 40);
System.out.println(MVEL.eval("age > 35 ? 'Senior' : 'Junior'", person)); // Senior
}
static class User {
String name;
int age;
User(String name, int age) { this.name = name; this.age = age; }
}
}JEXL
JEXL (Apache Commons JEXL) balances expressiveness and ease of use. Its syntax resembles Java and JavaScript, supporting arithmetic, logical operations, method calls, property access for Maps and Beans, collection handling, loops, and conditionals.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl3</artifactId>
<version>3.3</version>
</dependency>Example:
import org.apache.commons.jexl3.*;
public class JEXLExample {
public static void main(String[] args) {
JexlEngine jexl = new JexlBuilder().create();
// Simple expression
JexlExpression expr = jexl.createExpression("a + b * c");
JexlContext ctx = new MapContext();
ctx.set("a", 10);
ctx.set("b", 2);
ctx.set("c", 5);
System.out.println(expr.evaluate(ctx)); // 20
// Bean or Map property access
ctx.set("user", new User("Alice", 25));
System.out.println(jexl.createExpression("user.name").evaluate(ctx)); // Alice
// Loop script
String script = """
total = 0;
for (item : list) { total = total + item; }
return total;
""";
JexlScript jexlScript = jexl.createScript(script);
ctx.set("list", java.util.Arrays.asList(1,2,3,4,5));
System.out.println(jexlScript.execute(ctx)); // 15
}
static class User {
private String name;
private int age;
User(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
}
}JSP EL (Unified Expression Language)
Unified EL was created for the JSP Standard Tag Library and is now part of Jakarta EE. It uses ${...} or #{...} syntax, supporting property access (including nested), collection navigation, arithmetic, logical operators, implicit objects such as pageContext and param, and function calls. It is typically resolved by the web container when rendering JSP or Facelets pages.
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>5.0.0-M1</version>
</dependency>Simple offline evaluation (rarely used):
import jakarta.el.ExpressionFactory;
import jakarta.el.ValueExpression;
import jakarta.el.StandardELContext;
public class JSPELExample {
public static void main(String[] args) {
// ExpressionFactory factory = ExpressionFactory.newInstance();
// StandardELContext ctx = new StandardELContext(factory);
// ValueExpression ve = factory.createValueExpression(ctx, "${a + b}", Integer.class);
// Integer result = (Integer) ve.getValue(ctx);
}
}Selection Recommendations
High performance and rich built‑in features: Aviator.
Complex object navigation and conversion: OGNL or SpEL.
Very complex or highly dynamic business logic: Groovy.
Syntax close to Java and easy to learn: JEXL or MVEL.
General dynamic needs within the Spring ecosystem: SpEL.
Web view layer rendering: template engine’s own expression language (Thymeleaf, FreeMarker) or JSP EL.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Senior Xiao Ying
Dedicated to sharing Java backend technical experience and original tutorials, offering career transition advice and resume editing. Recognized as a rising star in CSDN's Java backend community and ranked Top 3 in the 2022 New Star Program for Java backend.
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.
