06 — Rules

Building Rules (Functional)

Lambda rules are the quickest way to define rules in rulii. You write conditions and actions as Java lambdas, and the framework matches parameter names to bindings automatically.

Required Imports

import static org.rulii.model.condition.Conditions.condition;
import static org.rulii.model.action.Actions.action;

The Simplest Rule

Rule rule = Rule.builder()
    .name("AlwaysTrue")
    .given(condition(() -> true))
    .then(action(() -> System.out.println("Fired!")))
    .build();

Condition + Action with Parameters

Parameter names in the lambda must match binding names:

Rule rule = Rule.builder()
    .name("AgeCheck")
    .given(condition((Integer age) -> age >= 18))
    .then(action(() -> System.out.println("Welcome!")))
    .build();

rule.run(age -> 25);  // Output: Welcome!

Multiple Then Actions

Rule rule = Rule.builder()
    .name("MultiAction")
    .given(condition((Integer score) -> score > 90))
    .then(action(() -> System.out.println("Excellent!")))
    .then(action((Binding<String> grade) -> grade.setValue("A")))
    .build();

Otherwise (Else Branch)

Rule rule = Rule.builder()
    .name("PassFail")
    .given(condition((Integer score) -> score >= 60))
    .then(action(() -> System.out.println("Pass")))
    .otherwise(action(() -> System.out.println("Fail")))
    .build();

rule.run(score -> 45);  // Output: Fail

PreCondition (Skip Guard)

A pre-condition decides whether the rule should even attempt to run. If it returns false, the rule is skipped entirely:

Rule rule = Rule.builder()
    .name("ConditionalRule")
    .preCondition(condition((Boolean featureEnabled) -> featureEnabled))
    .given(condition((Integer age) -> age >= 18))
    .then(action(() -> System.out.println("Running!")))
    .build();

// Pre-condition false → rule is SKIPPED (not FAIL)
rule.run(featureEnabled -> false, age -> 25);

Running Rules

// With lambda bindings
rule.run(name -> "Alice", age -> 30);

// With a Bindings object
Bindings b = Bindings.builder().standard();
b.bind("name", "Alice");
b.bind("age", 30);
rule.run(b);

// With a RuleContext
RuleContext ctx = RuleContext.builder().build(b);
RuleResult result = rule.run(ctx);

Complete Example: Date Validation

import static org.rulii.model.condition.Conditions.condition;
import static org.rulii.model.action.Actions.action;

Rule dateRule = Rule.builder()
    .name("DateConsistency")
    .given(condition((LocalDate startDate, LocalDate endDate)
        -> startDate != null && endDate != null && !endDate.isBefore(startDate)))
    .then(action(() -> System.out.println("Dates are valid")))
    .otherwise(action(() -> System.out.println("End date must be after start date")))
    .build();

dateRule.run(
    startDate -> LocalDate.of(2025, 1, 1),
    endDate -> LocalDate.of(2025, 12, 31)
);
// Output: Dates are valid

Warning

Due to the nature of how Lambdas are compiled in Java, generic parameter types and annotations are not persisted.

If you need those feaures you will have to define them manually. See example below:

Rule rule = Rule.builder()
        .name("MyLambdaRule", "Rule demonstrating ParameterDefinitionEditor usage")
        .given(
            Condition.builder()
                    .with((List<String> value, Integer threshold) -> {
                        return value != null && value.size() > threshold;
                    })
                    // Override param 0: type
                    .param(0)
                    .type(new TypeReference<List<String>>() {})
                    .description("The input text value to validate")
                    .build()
                    // Override param 1: type, description, and default value
                    .param(1)
                    .description("The minimum length threshold")
                    .defaultValueText("3")
                    .build()
                    .build())
                .build();