RepoPilotOpen in app →

j-easy/easy-rules

The simple, stupid rules engine for Java

Mixed

Stale — last commit 2y ago

weakest axis
Use as dependencyMixed

last commit was 2y ago; top contributor handles 92% of recent commits

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 8 active contributors
  • MIT licensed
  • CI configured
Show all 6 evidence items →
  • Tests present
  • Stale — last commit 2y ago
  • Single-maintainer risk — top contributor 92% of recent commits
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/j-easy/easy-rules?axis=fork)](https://repopilot.app/r/j-easy/easy-rules)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/j-easy/easy-rules on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: j-easy/easy-rules

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/j-easy/easy-rules shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 2y ago

  • 8 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Single-maintainer risk — top contributor 92% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live j-easy/easy-rules repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/j-easy/easy-rules.

What it runs against: a local clone of j-easy/easy-rules — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in j-easy/easy-rules | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 739 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>j-easy/easy-rules</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of j-easy/easy-rules. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/j-easy/easy-rules.git
#   cd easy-rules
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of j-easy/easy-rules and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "j-easy/easy-rules(\\.git)?\\b" \\
  && ok "origin remote is j-easy/easy-rules" \\
  || miss "origin remote is not j-easy/easy-rules (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java" \\
  && ok "easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java" \\
  || miss "missing critical file: easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java"
test -f "easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java" \\
  && ok "easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java" \\
  || miss "missing critical file: easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java"
test -f "easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java" \\
  && ok "easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java" \\
  || miss "missing critical file: easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java"
test -f "easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java" \\
  && ok "easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java" \\
  || miss "missing critical file: easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java"
test -f "easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java" \\
  && ok "easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java" \\
  || miss "missing critical file: easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 739 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~709d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/j-easy/easy-rules"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Easy Rules is a lightweight Java rules engine that lets you define business logic as discrete rule objects with conditions and actions, then execute them against a set of facts. It supports two programming models—annotation-based declarative rules (via @Rule, @Condition, @Action) and a fluent builder API—and can evaluate rules using expression languages like MVEL, SpEL, and JEXL. The core insight is that you don't need a heavy BRMS; just compose POJOs with condition/action pairs and iterate through them. Multi-module Maven monorepo: easy-rules-core/ contains the engine (API in org/jeasy/rules/api/, implementations in org/jeasy/rules/core/), and easy-rules-archetype/ provides a Maven archetype scaffold for new projects. Core abstractions are Rule (interface), RulesEngine (interface, with DefaultRulesEngine and InferenceRulesEngine implementations), Facts (fact container), and @Rule/@Condition/@Action annotations.

👥Who it's for

Java backend developers and enterprise architects who need to implement configurable business logic (pricing rules, eligibility checks, workflow decisions) without adopting heavyweight BRMS tools like Drools. Teams that want simple, testable rule definitions embedded in their applications rather than external rule files.

🌱Maturity & risk

Production-ready but in maintenance mode since December 2020. Version 4.1.1 is the active branch; only bug fixes are accepted. GitHub Actions CI is configured (.github/workflows/build.yml), suggesting automated testing, and the project is available on Maven Central. However, the maintenance-only status and freeze on new features indicates it's stable but no longer evolving.

Low risk for bug fixes, high risk if you need new features—the project explicitly rejects feature requests and only accepts maintenance patches. Single maintainer (benas@icloud.com per pom.xml) creates succession risk. Dependency surface is modest (Java 436KB codebase suggests lean dependencies), but no visibility into test coverage or recent commit frequency from the provided data.

Active areas of work

Project is in maintenance mode—no active development visible. The most recent tag was 4.1.0 (June 2020), with a 4.1.1-SNAPSHOT in pom.xml suggesting only snapshot/patch builds. No open PRs or milestones mentioned in provided data. Focus is on keeping the library stable and compatible rather than adding features.

🚀Get running

Clone and build with Maven: git clone https://github.com/j-easy/easy-rules.git && cd easy-rules && mvn clean install. Then explore examples in easy-rules-archetype/src/main/resources/archetype-resources/ or create a new archetype project: mvn archetype:generate -DarchetypeGroupId=org.jeasy -DarchetypeArtifactId=easy-rules-archetype -DarchetypeVersion=4.1.1.

Daily commands: This is a library, not a runnable application. Build it: mvn clean install. To use it in your own project, add dependency: <dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-core</artifactId><version>4.1.1</version></dependency>. Then instantiate rules via annotations or RuleBuilder and execute with RulesEngine.fire(rules, facts).

🗺️Map of the codebase

  • easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java — Core interface defining the rules engine contract; every contributor must understand the primary execution abstraction.
  • easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java — Default implementation of the rules engine; contains the main rule evaluation loop and execution logic.
  • easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java — Core Rule interface defining condition/action pattern; fundamental abstraction for all rule definitions.
  • easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java — Reflection-based proxy for annotated rules; bridges annotation-based and interface-based rule definitions.
  • easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java — Core annotation for declarative rule definition; primary entry point for users writing rules declaratively.
  • easy-rules-core/src/main/java/org/jeasy/rules/api/Facts.java — Facts container passed to rules during execution; defines the working memory shared across all rules.

🛠️How to make changes

Add a New Annotated Rule

  1. Create a POJO class and mark it with @Rule annotation from easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java (your-project/src/main/java/MyCustomRule.java)
  2. Add a public method with @Condition annotation that takes Facts parameter and returns boolean (your-project/src/main/java/MyCustomRule.java)
  3. Add a public method with @Action annotation that takes Facts parameter and returns void (your-project/src/main/java/MyCustomRule.java)
  4. Optionally add @Priority annotation method to control rule execution order (your-project/src/main/java/MyCustomRule.java)
  5. Use RuleProxy from easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java to register the rule with the engine (your-project/src/main/java/YourEngine.java)

Add a Programmatic Rule

  1. Import RuleBuilder from easy-rules-core/src/main/java/org/jeasy/rules/core/RuleBuilder.java (your-project/src/main/java/YourEngine.java)
  2. Use RuleBuilder.aNewRule() to create a Rule with fluent API, setting name, description, priority, condition, and action (your-project/src/main/java/YourEngine.java)
  3. Register the built rule with DefaultRulesEngine from easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java (your-project/src/main/java/YourEngine.java)

Add a Custom Expression Language

  1. Create a new module (e.g., easy-rules-myexpr) mirroring easy-rules-jexl structure (easy-rules-myexpr/pom.xml)
  2. Implement Condition interface from easy-rules-core/src/main/java/org/jeasy/rules/api/Condition.java for your expression language (easy-rules-myexpr/src/main/java/org/jeasy/rules/myexpr/MyExprCondition.java)
  3. Implement Action interface from easy-rules-core/src/main/java/org/jeasy/rules/api/Action.java for your expression language (easy-rules-myexpr/src/main/java/org/jeasy/rules/myexpr/MyExprAction.java)
  4. Use your custom Condition/Action classes when building rules with RuleBuilder or as part of rule definitions (your-project/src/main/java/YourEngine.java)

Monitor Rule Execution

  1. Implement RuleListener interface from easy-rules-core/src/main/java/org/jeasy/rules/api/RuleListener.java to observe individual rule events (your-project/src/main/java/MyRuleListener.java)
  2. Implement RulesEngineListener interface from easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngineListener.java to observe engine-level events (your-project/src/main/java/MyEngineListener.java)
  3. Register listeners with the RulesEngine via registerRuleListener() and registerEngineListener() methods (your-project/src/main/java/YourEngine.java)

🔧Why these technologies

  • Java Reflection & Annotations — Enables declarative rule definition without boilerplate; users annotate POJOs with @Rule, @Condition, @Action instead of implementing interfaces
  • JEXL (JavaServer Pages Expression Language) — Optional expression-based condition/action evaluation; allows non-Java-fluent users to define rules as expressions (easy-rules-jexl module)
  • Maven Archetype — Quickstart

🪤Traps & gotchas

No environment variables or external services required—Easy Rules is standalone. However, annotation processing depends on reflection at runtime, so rules must be on the classpath and discoverable by RuleProxy. Expression language rules (MVEL, SpEL, JEXL) require additional optional dependencies not bundled with core; you must add them to your pom.xml. No obvious version constraints in the snippet, but since it's in maintenance mode (Java version not specified—may require Java 8+), verify compatibility with your JDK.

🏗️Architecture

💡Concepts to learn

  • Rule Engine / Forward Chaining — Easy Rules implements a rules engine pattern where conditions are checked and actions are fired; the InferenceRulesEngine variant adds forward-chaining (facts added by actions can trigger new rule evaluations) which is fundamental to understanding how the library scales beyond simple one-pass rule execution.
  • Annotation-Driven Reflection / Introspection — The RuleProxy class uses Java reflection to scan @Rule, @Condition, and @Action annotations at runtime and dynamically construct Rule objects; this is the bridge between declarative rule definitions and the engine's internal execution model, and understanding it is key to knowing how Easy Rules works under the hood.
  • Strategy Pattern (Pluggable Engines) — Easy Rules defines RulesEngine as an interface with multiple implementations (DefaultRulesEngine for sequential firing, InferenceRulesEngine for iterative inference); this lets users swap engines without changing rule code, and is a core design pattern for the library.
  • Fluent Builder API — The RuleBuilder class provides a readable, method-chaining interface for programmatically constructing rules (alternative to annotations); this pattern is essential for dynamic rule generation and is visible in the README examples.
  • Priority-Based Rule Ordering — Rules have a Priority annotation/field; the engine sorts and executes rules by priority before evaluating conditions, allowing control over which rules run first. This is critical for conflict resolution in complex rule sets.
  • Fact Container Pattern — The Facts class holds named objects (context data) that are passed to rules; rules reference facts by name (e.g., @Fact("rain") boolean rain). This decoupling of rule logic from data sources is a design pattern that enables rule reuse across different contexts.
  • Expression Language Adapters (MVEL, SpEL, JEXL) — Easy Rules can evaluate rule conditions using external expression languages rather than Java code; this allows non-developers to write rules in a DSL. The adapter pattern (not visible in core but mentioned in README) bridges the engine to different EL implementations.
  • drools/drools — Industry-standard BRMS with full DRL language, complex event processing, and constraint satisfaction; Easy Rules is a lightweight alternative for simpler use cases.
  • mvel/mvel — Expression language that Easy Rules uses as an optional plug-in for rule conditions and actions; understanding MVEL is needed if you use the SpEL/MVEL rule modules.
  • spring-projects/spring-framework — Easy Rules integrates well with Spring's dependency injection and SpelExpressionParser; many users embed Easy Rules rules within Spring applications.
  • apache/commons-jexl — JEXL is one of three supported expression languages for Easy Rules (as of version 4.1); provides an alternative to MVEL for rule expressions.
  • j-easy/easy-batch — Companion project from the same author for batch processing; often used alongside Easy Rules to apply rules over large datasets row-by-row.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for InferenceRulesEngine

The InferenceRulesEngine.java exists but there are no visible test files for it in easy-rules-core/src/test. This engine likely has different behavior than DefaultRulesEngine (supports rule chaining and fact inference), making it critical to have dedicated integration tests. This is valuable because inference engines are complex and need thorough coverage to prevent regressions in maintenance mode.

  • [ ] Create easy-rules-core/src/test/java/org/jeasy/rules/core/InferenceRulesEngineTest.java
  • [ ] Add tests for rule chaining (rules triggering other rules)
  • [ ] Add tests for fact insertion during rule execution
  • [ ] Add tests for engine termination conditions in inference loops
  • [ ] Add edge case tests (circular dependencies, max iterations)

Add validation tests for RuleDefinitionValidator and edge cases

The test directory shows many test files for invalid annotation scenarios (AnnotatedRuleWithActionMethodHavingMoreThanOneArgumentOfTypeFacts.java, etc.) but RuleDefinitionValidator.java itself has no visible dedicated test class. This validator is critical for catching malformed rules early. Add systematic tests covering all validation rules to prevent future bugs when validating annotated rules.

  • [ ] Create easy-rules-core/src/test/java/org/jeasy/rules/core/RuleDefinitionValidatorTest.java
  • [ ] Add tests for each invalid annotation scenario already listed in test/annotation folder
  • [ ] Add tests for valid rule definitions passing validation
  • [ ] Add tests for edge cases (null parameters, empty rule sets)
  • [ ] Verify each validation error message is clear and actionable

Add missing documentation for Rules API composition and fluent RuleBuilder usage

The RuleBuilder.java and RuleProxy.java are core to the framework but the README only shows basic examples. The archetype in easy-rules-archetype contains HelloWorldRule.java but doesn't demonstrate advanced patterns. Add a dedicated doc or enhance README with specific examples showing: (1) RuleBuilder fluent API usage, (2) Rules composition, (3) difference between annotation-based and programmatic rule definition.

  • [ ] Create docs/RULE_BUILDER_GUIDE.md with RuleBuilder fluent API examples
  • [ ] Add before/after examples showing programmatic vs annotation-based approach
  • [ ] Document RuleProxy usage and when it's automatically applied
  • [ ] Add example of composing multiple rules with Rules.java
  • [ ] Link new guide from README.md in main section

🌿Good first issues

  • Add comprehensive JavaDoc comments to org/jeasy/rules/core/AbstractRulesEngine.java and RuleProxy.java—these are complex classes with significant reflection and delegation logic but minimal inline documentation, making onboarding hard.
  • Create a dedicated integration test suite for InferenceRulesEngine.java demonstrating forward-chaining scenarios (e.g., rules that add facts which trigger subsequent rules); the file list shows no separate test examples for inference.
  • Write a troubleshooting guide in the README or Wiki documenting common pitfalls: missing @Fact parameter names, annotation inheritance issues, priority ordering gotchas, and how to debug with RuleListener—the archetype example is too minimal.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • d445083 — Update README.md (fmbenhassine)
  • 6de08b4 — Add tests for null checks in DefaultRulesEngine (fmbenhassine)
  • 2228fb2 — Add aston2016 to contributors list (fmbenhassine)
  • c994ffb — Fix NullPointerException in DefaultRulesEngine (aston)
  • ab75210 — Update year in license header (fmbenhassine)
  • 8109230 — Add null checks in InferenceRulesEngine (fmbenhassine)
  • 4eac660 — Update README.md (fmbenhassine)
  • 36d7290 — Add LICENSE.md (fmbenhassine)
  • 393144f — [maven-release-plugin] prepare for next development iteration (fmbenhassine)
  • 702a368 — [maven-release-plugin] prepare release easy-rules-4.1.0 (fmbenhassine)

🔒Security observations

Easy Rules is a maintenance-mode rules engine with a relatively clean architecture. Primary security concerns stem from its heavy use of reflection and dynamic method invocation for rule execution. While the core library itself doesn't expose critical vulnerabilities in the provided files, implementers must be cautious when loading rules from untrusted sources. The framework lacks built-in authorization and input validation mechanisms that should be implemented at the application level. No hardcoded credentials, SQL injection vectors, XSS risks, or Docker issues were identified in the provided file structure. Dependencies should be regularly audited given the project's maintenance status.

  • Medium · Reflection-Based Rule Execution — easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java. The codebase uses Java reflection heavily (RuleProxy, annotation processing) to dynamically invoke methods on rule objects. This could potentially be exploited if untrusted rule classes are loaded, allowing arbitrary method execution. Fix: Implement strict validation and sandboxing of rule classes. Use a whitelist approach for allowed rule annotations and methods. Consider security manager policies to restrict reflection capabilities.
  • Medium · Unsafe Annotation Processing — easy-rules-core/src/main/java/org/jeasy/rules/core/RuleDefinitionValidator.java, RuleProxy.java. The framework uses annotation-based rule definition with dynamic method invocation. There's potential risk if rule metadata (annotations) can be manipulated or if rule classes are loaded from untrusted sources. Fix: Validate all annotations at load time. Implement checks to ensure only expected method signatures are invoked. Use sealed classes or final modifiers where appropriate.
  • Low · Missing Input Validation in Facts API — easy-rules-core/src/main/java/org/jeasy/rules/api/Facts.java. The Facts API (Facts.java) accepts arbitrary objects without validation. If facts are populated from external sources, malicious objects could be injected into the rule evaluation context. Fix: Implement input validation and sanitization for facts. Consider restricting fact types to approved classes. Add type checking at runtime.
  • Low · Potential Information Disclosure via Exceptions — easy-rules-core/src/main/java/org/jeasy/rules/core/NoSuchFactException.java. NoSuchFactException and other custom exceptions may expose internal implementation details if error messages aren't properly sanitized. Fix: Ensure exception messages don't leak sensitive information. Implement proper exception handling at the application level with generic user-facing error messages.
  • Low · No Apparent Authorization Controls — easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java. The rules engine lacks built-in authorization mechanisms. There's no indication of rule access control or validation of who can execute which rules. Fix: Implement rule-level access controls. Add authorization checks before rule execution. Consider integrating with security frameworks like Spring Security.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · j-easy/easy-rules — RepoPilot