ARTICLE AD BOX
I am working on an application where it dynamically generates and executes some Spring Expression Language (SpEL) expressions.
I am facing a few performance issues, and after tracking it down a bit, I found out it was happening because the SpEL compiler refuses to compile an expression if the whole thing hasn't been run normally (this part is expected). In my case this was happening because of a logical operator.
I noticed that in case of logical or ( || )
when you use a logical ( || ) operator separating two expressions in SpEL. The first half of the expression is true most of the time; the second half doesn't execute. This leads to the compiler not having enough info about the second half of the expression to compile it.Similarly for logical ( && ) if the first half is false.
I have a minimal example of this behavior.
package org.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Configuration; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.SpelCompilerMode; import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.scheduling.annotation.EnableAsync; @EnableAsync @Configuration @SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); ExpressionParser parser = new SpelExpressionParser( new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, Main.class.getClassLoader()) ); Expression expression = parser.parseExpression("(#var1) || (#var2)"); StandardEvaluationContext context = new StandardEvaluationContext(); for (int i = 0; i < 10000; i++) { context.setVariable("var1", true); context.setVariable("var2", false); expression.getValue(context, Object.class); } System.out.println("End"); } }If you have
logging.level.org.springframework.expression=TRACEYou will see the logs say
2025-11-26T12:58:18.891+05:30 DEBUG 20156 --- [ main] o.s.e.spel.standard.SpelCompiler : SpEL: unable to compile (#var1 or #var2) 2025-11-26T12:58:18.891+05:30 DEBUG 20156 --- [ main] o.s.e.spel.standard.SpelCompiler : SpEL: unable to compile (#var1 or #var2) 2025-11-26T12:58:18.891+05:30 DEBUG 20156 --- [ main] o.s.e.spel.standard.SpelCompiler : SpEL: unable to compile (#var1 or #var2) 2025-11-26T12:58:18.891+05:30 DEBUG 20156 --- [ main] o.s.e.spel.standard.SpelCompiler : SpEL: unable to compile (#var1 or #var2) 2025-11-26T12:58:18.891+05:30 DEBUG 20156 --- [ main] o.s.e.spel.standard.SpelCompiler : SpEL: unable to compile (#var1 or #var2) 2025-11-26T12:58:18.891+05:30 DEBUG 20156 --- [ main] o.s.e.spel.standard.SpelCompiler : SpEL: unable to compile (#var1 or #var2) 2025-11-26T12:58:18.891+05:30 DEBUG 20156 --- [ main] o.s.e.spel.standard.SpelCompiler : SpEL: unable to compile (#var1 or #var2) EndBut if var1 is false or sometimes false, the expression gets compiled.
Are there ways to write the expressions so that both halves are computed and thus the expression gets compiled? Or any other workarounds?
