MVEL eval() with .equals() Fails on First Execution in Drools 10 - Works with == Operator

5 views
Skip to first unread message

Geeta Dhamak

unread,
Apr 21, 2026, 6:42:23 AM (8 days ago) Apr 21
to Drools Usage

Hi Drools Team,

We've encountered a critical issue with MVEL dialect in Drools 10 where .equals() method calls on string literals within eval() expressions fail on first execution but work correctly on subsequent executions. Using the == operator instead resolves the issue immediately.


Problem Description

When using MVEL dialect with eval() containing .equals() on string literal constants, rules fail to fire on first execution but work correctly on second and subsequent executions.


Reproducible ExampleFailing DRL (First execution: 0 rules fired, Second execution: Rules fire correctly)
drools
package com.example.rules;
 
import com.example.model.Configuration;
import com.example.model.PaymentConfig;
 
global com.example.RuleContext ruleContext;
 
rule "PaymentConfig_Rule1"
salience 90
agenda-group "PaymentConfig"
dialect "mvel"
when
config : Configuration()
eval((config.getFeatureEnabled() != null &&
config.getFeatureEnabled().equals("N")) &&
"Y".equals("Y")) // ← This constant .equals() causes first-execution failure
then
PaymentConfig paymentConfig = new PaymentConfig();
paymentConfig.setEnabled("Y");
paymentConfig.setMode("CHECK");
insert(paymentConfig);
end

Observed Behavior:

  • First execution: eval("Y".equals("Y")) returns false or null → 0 rules fire

  • Second execution: Expression cache is warmed up → Rules fire correctly

  • All subsequent executions: Work correctly


Working DRL (All executions: Rules fire correctly)
drools
package com.example.rules;
 
import com.example.model.Configuration;
import com.example.model.PaymentConfig;
 
global com.example.RuleContext ruleContext;
 
rule "PaymentConfig_Rule1"
salience 90
agenda-group "PaymentConfig"
dialect "mvel"
when
config : Configuration()
eval((config.getFeatureEnabled() != null &&
config.getFeatureEnabled().equals("N")) &&
"Y" == "Y") // ← Using == operator instead of .equals()
then
PaymentConfig paymentConfig = new PaymentConfig();
paymentConfig.setEnabled("Y");
paymentConfig.setMode("CHECK");
insert(paymentConfig);
end

Observed Behavior:

  • All executions: Work correctly from first execution onwards


Minimal Reproducible Example
drools
package com.example.test;
 
rule "TestRule_Failing"
dialect "mvel"
when
eval("Y".equals("Y")) // ← Fails on first execution
then
System.out.println("Rule fired!");
end
 
rule "TestRule_Working"
dialect "mvel"
when
eval("Y" == "Y") // ← Works on first execution
then
System.out.println("Rule fired!");
end

Root Cause Analysis

Based on our investigation, the issue appears to be related to MVEL's constant expression optimization in Drools 10:

  1. With .equals() method call:

    • MVEL attempts to pre-compile "Y".equals("Y") as a constant expression

    • During first compilation, the method reference is not fully initialized

    • The cached expression returns incorrect result (null or false)

    • On second execution, the cached expression is warmed up and works correctly

  2. With == operator:

    • MVEL uses native operator evaluation (no method compilation needed)

    • No reflection or method resolution required

    • Works immediately on first execution


Test Environment
  • Drools Version: 10.x

  • Dialect: MVEL

  • Expression Type: eval() with string literal constants

  • Pattern: Decision table generated rules with constant checks

  • Java Version: 11+


WorkaroundsOption 1: Use == instead of .equals() (Recommended)
drools
eval("Y" == "Y") // Works on first execution
Option 2: Change dialect to Java
drools
dialect "java"
when
eval("Y".equals("Y")) // Works correctly with Java dialect
Option 3: Avoid constant expressions
drools
eval(("" + "Y").equals("Y")) // String concatenation prevents optimization
Option 4: Use Boolean.valueOf()
drools
eval(Boolean.valueOf("Y".equals("Y"))) // Method call prevents optimization

Questions for the Team
  1. Is this a known issue with MVEL constant optimization in Drools 10?

  2. Is there a configuration to disable aggressive constant folding for .equals() calls?

  3. Should we consider this a bug or expected MVEL behavior?

  4. What is the recommended approach for decision tables that generate constant comparisons?

  5. Are there plans to address this in future Drools releases?


Impact

This issue affects production systems where rules must fire correctly on first execution (e.g., first user login, cold start scenarios, batch processing). The workaround using == is simple but requires updating all affected decision tables and rules.


Additional Observations
  • The issue is reproducible across different rule packages

  • It affects decision table generated rules where constant checks are common

  • Dummy fireAllRules() before actual execution does NOT resolve the issue (both return 0)

  • The problem is specific to string literal .equals() calls, not variable comparisons


Any insights or guidance would be greatly appreciated!

Best regards,
Development Team


Reply all
Reply to author
Forward
0 new messages