O que Regras em Cascata na JVM faz?
Dependência (Maven): com.rulescascade:rules-cascade-core (Java 17+, nenhuma outra dependência de runtime;
package com.rulescascade). Gradle: implementation("com.rulescascade:rules-cascade-core:<version>").
Os bundles vêm de rcas compile --all em build/rules/. Nunca avalie o YAML em tempo de execução e nunca
copie uma regra para o código.
Carregue uma vez, avalie por requisição
import com.rulescascade.*;
// Um bean / singleton, criado na inicialização. Uma exceção aqui deve parar a aplicação.
RuleSet rules = RuleSet.fromBundle((Map<String, Object>) Json.parse(Files.readString(Path.of("build/rules/<ruleset-id>.bundle.json"))));
List<String> missing = rules.missingOperators(); // operadores personalizados que as regras precisam
if (!missing.isEmpty()) throw new IllegalStateException("operadores não registrados: " + missing);
Quando o serviço analisa JSON com Jackson, habilite DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS
para que os valores cheguem ao mecanismo com exatidão.
Prefira rules.enforce(request) (desde 1.0.0-alpha.7): ele retorna o resultado permitido ou lança
com.rulescascade.RuleViolationException, cujo problem() é a resposta 422, igual em todo runtime
Rule Cascade. Um manipulador responde a ele para cada endpoint:
@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());
}
}
Para anotação em métodos de controller, copie @EnforceRules e RuleEnforcementAspect do
exemplo Spring Boot (https://rulescascade.com/reference/examples/backend-spring-boot/); ele precisa de
spring-boot-starter-aspectj (spring-boot-starter-aop antes do Spring Boot 4). Cada endpoint que
altera estado segue quatro etapas:
- Avalie no servidor:
rules.evaluate(EvaluationRequest.builder(entity, operation).data(data).original(original).actor(...).build(), Channel.SERVER). O actor vem do contexto de segurança, nunca de um cabeçalho que o chamador controla. - Recuse ao negar: quando
!result.allowed(), lance umaRuleViolationException(result)e mapeie uma vez, em um@RestControllerAdvice/ mapeador de exceção, para 422ProblemDetailcomtype: urn:rule-cascade:rule-violatione o resultado (result.toMap()) como propriedade. - Persista, após aplicar os efeitos
compute(effect.type()évalue): o valor do servidor é armazenado. - Execute
result.commands()após o commit (@TransactionalEventListener(phase = AFTER_COMMIT)ou um outbox), uma vez poridempotencyKey.
Colocação: Spring um @Configuration com um RuleSet @Bean e um serviço por entidade que constrói a
requisição; Quarkus/Micronaut um produtor @Singleton. Kotlin e Scala chamam a mesma API.
RuleSetHolder recarrega bundles em um intervalo ou cronograma e mantém as últimas regras válidas.
Substituindo validação existente
rcas analyze --module <module> lista anotações Bean Validation, validadores Spring e
@PreAuthorize, regras Drools .drl, verificações manuais, limites nomeados (MAX_QUANTITY = 10),
comparações com números e branches switch em um status. Um candidato com drift significa que o mesmo
nome tem outro valor no frontend: um conjunto de regras deve decidir para ambos. Mantenha verificações de tipo
@NotNull/@Size no DTO se desejar; mova decisões de negócio para regras. Adicione um teste de paridade (JUnit
@ParameterizedTest sobre as mesmas entradas para a verificação antiga e o mecanismo) e então delete a verificação antiga.
Testes
Afirme decision e códigos de resultado, não textos de mensagem. Testes dourados no conjunto de regras (rcas check)
testam as regras; CI executa rcas check e rcas compile --all antes de mvn verify / gradle test.
Referência: https://rulescascade.com/usage/java/ e https://rulescascade.com/playbooks/backend-api/