Skip to content

2.0.0-RC1

Pre-release
Pre-release

Choose a tag to compare

@rapatao rapatao released this 31 Aug 22:30
· 2 commits to main since this release
2.0.0-RC1
2ad6249

Release candidate for 2.0.0, published to Maven Central as 2.0.0-RC1.

The major bump is not cosmetic: rule evaluation results changed. Re-run your
rule set against this candidate before adopting 2.0.0.

Breaking

Numeric comparison is value based. Equals compared operands with ==, and
BigDecimal.equals is scale sensitive, so a rule comparing 10 against a
BigDecimal("10.00") field answered false. It compares with compareTo now
and answers true. BigInteger operands convert directly rather than through
toLong, which overflowed above Long.MAX_VALUE, and collections compare
element by element under the same rule. The same rule against the same input can
return a different boolean than it did in 1.6.0.

KotlinContext(Evaluator, Map<String, Any?>) is now
KotlinContext(Evaluator, Any).
The Kotlin engine no longer flattens the input
into a map of every path; it resolves the paths a rule names, on demand.

GraalJSEvaluator gained a reuseContextPerThread parameter. Source
compatible, but the primary constructor's JVM signature changed, so recompile
against this version rather than swapping the jar.

ifFail on a group expression keeps its matchers. It rebuilt the expression
from left, operator and right only, so allMatch(...) ifFail FALSE
discarded every matcher and produced an expression that then failed validation.

Fixed

  • An operator whose name carries an uppercase letter is reachable again. Names
    were stored lowercased but looked up raw, so a custom myOperator could never
    be resolved.
  • A quoted literal spanning lines parses as a literal. The check was a regex
    whose . does not match a newline, so the literal fell through to path
    resolution and threw NoSuchElementException.
  • The Unknown operator: message printed null rather than the operator name.

Performance

  • Kotlin: operand paths resolve lazily instead of flattening the whole input
    per evaluation, so cost tracks the rule rather than the input size. Operands
    skip the number parses unless they start like a number.
  • Rhino: one sealed set of standard objects is shared across evaluations and
    each evaluation runs in a child scope.
  • GraalJS: opt in with reuseContextPerThread = true to keep one context per
    thread.

See BENCHMARKS.md
for the measured figures and the trade offs of each.

Checking the candidate

implementation "com.rapatao.ruleset:kotlin-evaluator:2.0.0-RC1"

Worth exercising specifically: any rule comparing numbers where scale differs
(10 against 10.00), anything constructing KotlinContext directly, and any
GraalJSEvaluator built with positional constructor arguments.

Full Changelog: 1.6.0...2.0.0-RC1