JVM 上の Rule Cascade
依存関係(Maven): com.rulescascade:rules-cascade-core(Java 17+、その他のランタイム依存関係なし;
パッケージ com.rulescascade)。Gradle: implementation("com.rulescascade:rules-cascade-core:<version>")。
バンドルは rcas compile --all によって build/rules/ に生成されます。実行時に YAML を評価したり、ルールをコードにコピーしたりしないでください。
一度ロードし、リクエストごとに評価
import com.rulescascade.*;
// 1 つの Bean / シングルトンとして、起動時に作成する。ここで例外が発生した場合はアプリケーションを停止させること。
RuleSet rules = RuleSet.fromBundle((Map<String, Object>) Json.parse(Files.readString(Path.of("build/rules/<ruleset-id>.bundle.json"))));
List<String> missing = rules.missingOperators(); // ルールが必要とするカスタム演算子
if (!missing.isEmpty()) throw new IllegalStateException("未登録の演算子: " + missing);
Jackson で JSON をパースする場合、DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS を有効にして、金額が正確にエンジンに渡るようにします。
rules.enforce(request) を使用することを推奨(1.0.0-alpha.7 以降): 許可された結果を返すか、com.rulescascade.RuleViolationException をスローします。この例外の problem() は 422 応答で、すべての Rule Cascade ランタイムで共通です。1 つのハンドラーですべてのエンドポイントに応答します:
@RestControllerAdvice
class RuleErrors {
@ExceptionHandler(RuleViolationException.class)
ResponseEntity<Map<String, Object>> denied(RuleViolationException e) {
return ResponseEntity.status(e.status()).contentType(MediaType.APPLICATION_PROBLEM_JSON).body(e.problem());
}
}
コントローラーメソッドにアノテーションを付ける場合は、Spring Boot の例(https://rulescascade.com/reference/examples/backend-spring-boot/)から @EnforceRules と RuleEnforcementAspect をコピーしてください; これには spring-boot-starter-aspectj が必要です(Spring Boot 4 より前は spring-boot-starter-aop)。すべての状態変更エンドポイントは次の 4 つの手順に従います:
- サーバー上で評価:
rules.evaluate(EvaluationRequest.builder(entity, operation).data(data).original(original).actor(...).build(), Channel.SERVER)アクターはセキュリティコンテキストから取得し、呼び出し元が制御するヘッダーからは決して取得しません。 - 拒否時は拒否:
!result.allowed()の場合、RuleViolationException(result)をスローし、@RestControllerAdvice/ 例外マッパーで一度だけマッピングして、422ProblemDetail(type: urn:rule-cascade:rule-violationと結果(result.toMap())をプロパティとして含む)にします。 - 永続化:
compute効果(effect.type()がvalue)を適用した後、サーバーの値を保存します。 - コミット後に
result.commands()を実行:(@TransactionalEventListener(phase = AFTER_COMMIT)またはアウトボックスを使用)各idempotencyKeyに対して 1 回。
配置: Spring では @Configuration に RuleSet @Bean と、リクエストを構築するエンティティごとのサービス; Quarkus/Micronaut では @Singleton プロデューサー。Kotlin と Scala も同じ API を呼び出します。
RuleSetHolder は一定間隔または cron スケジュールでバンドルを再読み込みし、最後に有効だったルールを保持します。
既存のバリデーションの置き換え
rcas analyze --module <module> は、Bean Validation アノテーション、Spring Validator、@PreAuthorize、Drools .drl ルール、手書きチェック、名前付き制限(MAX_QUANTITY = 10)、数値との比較、ステータスに基づく switch 分岐をリストアップします。drift を持つ候補は、同じ名前がフロントエンドで別の値を持っていることを意味します: 1 つのルールセットが両方に対して決定する必要があります。必要に応じて、DTO に @NotNull/@Size 型チェックを残しても構いません; ビジネス上の決定はルールに移行してください。パリティテスト(古いチェックとエンジンの同じ入力に対する JUnit @ParameterizedTest)を追加し、その後古いチェックを削除します。
テスト
decision と検出コードをアサートし、メッセージテキストはアサートしないでください。ルールセット内のゴールデンテスト(rcas check)はルールをテストします; CI は mvn verify / gradle test の前に rcas check と rcas compile --all を実行します。
参考: https://rulescascade.com/usage/java/ および https://rulescascade.com/playbooks/backend-api/