Getting Started
What's New in 2.1.0
Released October 2026
Introspection — Rules That Describe Themselves
The headline of 2.1.0: everything a Rule, RuleSet, or RuleFlow is made of can now be read off the built object without running it — the foundation for rulii-explorer. Conditions, actions, and functions report an ExpressionInfo (script source, compiled method, or composite operator + operands), every RuleFlow command describes itself through CommandInfo, and definitions carry input parameters, context labels, result types, and error handlers.
// What is this condition made of?
ExpressionInfo expr = rule.getCondition().getExpression();
expr.kind(); // SCRIPT, COMPILED or COMPOSITE
expr.sourceText(); // the script text as written
// What does this flow do, step by step?
ruleFlow.getDefinition().getCommands()
.forEach(cmd -> System.out.println(cmd));
Category & Tags
Rules, RuleSets, and RuleFlows can now say where they belong and what they are about — for tools that group and filter them. Use @Category("Pricing/Discounts") and @Tags({"vip", "discount"}) on @Rule classes, or category(...) / tags(...) on the rule, validation rule, rule set, and rule flow builders. Both are purely descriptive: rulii never reads them when it runs.
Accurate Source Tracking
SourceDefinition.build()now records the real caller's location instead of pointing at itself- Builders accept an explicit source via
source(SourceDefinition)— loaders can record where an artifact was declared (rulii-spring records the XML file and line) - New
SourceDefinition.forFile(fileName, line)andforClass(type)factories - Class-based rules now record their rule class as the source, not the code that called the builder
GraalJS Scripting Overhaul
- Polyglot context leak fixed — contexts are now released after each evaluation; under sustained evaluation the old behavior exhausted the heap
- JavaScript values are detached as they cross into Java: arrays become
ArrayLists, object literals becomeLinkedHashMaps,Dates becomeInstants — no more live proxies - Nashorn compatibility mode on by default — scripts read Java bean properties directly:
ctx.person.nameinstead ofctx.person.getName() - Factory aliases: every spelling GraalJS registers (
JS,JavaScript,ECMAScript, ...) now resolves to the configured factory - New
ScriptProcessorManager.unregister(factory)lets integrations remove factories tied to their own lifecycle
Leak Fixes & API Polish
- Definition cache leak fixed — building conditions, actions, functions, or rules from lambdas no longer grows the heap without bound
RuleRegistry.getNames()returns the keys every runnable can be looked up by- RuleSet and RuleFlow builders gain
param(name, type, required, description)overloads;InputParametergains a description ValidationRuleBuilder.build()no longer drops the builder's description;ValueValidationRule.getValueName()is public
Breaking changes: RuleRegistry.getNames() is abstract — custom registries must implement it; ContainerCommand.getBody() is now public; RuleSetDefinition.getStopActionDefinition() is deprecated — use getStopConditionDefinition().
XML Provenance, Category & Tags
rulii-spring 2.1.0 adds the Spring side of introspection: every bean definition loaded from @RuleScan(xmlLocations) carries the XML file and line it was declared on, and XML-built artifacts report them as their SourceDefinition. Every artifact element takes category and tags attributes, with file-level defaults:
<r:defaults category="Pricing" tags="checkout"/>
<r:rule name="ApproveRule" category="Pricing/Approvals" tags="vip"
given="#ctx.total >= 100" then="#ctx.approved = true"/>
Bean Lifecycle Hardening
- Closing a child context no longer shuts down the parent's rule infrastructure (Spring Cloud bootstrap,
SpringApplicationBuilder.child(),@ContextHierarchy) - The
rulii.executorServicebean is now aRuleExecutorServicethat shuts down gracefully with the context — waits up torulii.executor.awaitTerminationSeconds(default 10), then interrupts ScriptProcessorFactorybeans are unregistered from the JVM-wideScriptProcessorManagerwhen the context closes — closed contexts are no longer reachable from the process-wide registryRuleRegistrarMetaInfo.xmlFiles()lists the XML files that were actually loaded, in load order