Skip to content

Repository files navigation

Guard4j

– Guard4j events describe what happens in your domain, not how you measure it.

Production-grade error handling and observability for Java applications. Framework-agnostic core with seamless Spring Boot, Quarkus, and Micronaut integration.

The Problem

Enterprise Java applications typically suffer from inconsistent error handling that breaks down in production:

  • Generic Map<String, Object> error responses that clients can't reliably parse
  • Framework-specific error handling that doesn't work when you switch frameworks
  • No built-in observability - errors disappear into logs without metrics or alerting
  • Testing nightmares where MockMvc tests pass but production servlet errors fail

The Solution

Guard4j provides type-safe error handling with automatic observability that works identically across all major Java frameworks:

// Clean, fluent error creation with business contextthrownewAppException(ErrorCodes.BUSINESS_RULE_VIOLATION)
.withData("rule", "DAILY_TRANSFER_LIMIT")
.withData("limit", 10000)
.withData("attempted", 15000);

Emitter Factory Pattern

publicclassPaymentService {
privatestaticfinalEmitterevents = Guard4j.getEmitter(PaymentService.class);
publicvoidprocessPayment(Paymentpayment) {
// Single event call generates both metrics and structured logsevents.info(newPaymentProcessedEvent(payment.getId(), payment.getAmount()));
}
}
{
"timestamp": "2024-01-15T10:30:00Z",
"status": 422,
"error": "Unprocessable Entity",
"code": "BUSINESS_RULE_VIOLATION",
"data": {
"userId": "user123",
"rule": "DAILY_TRANSFER_LIMIT",
"limit": 10000,
"attempted": 15000,
"retryable": false,
"severity": "medium"
}
}

Key Features

  • Type-safe error responses - No more Map<String, Object> - structured, predictable JSON
  • Framework-agnostic - Same error handling code works in Spring Boot, Quarkus, and Micronaut
  • Automatic observability - Built-in metrics, structured logging, and alerting integration
  • Production-ready - Configurable alert levels, retry logic, and environment-specific behavior
  • Zero-config setup - Add dependency, start throwing better exceptions

Quick Start (Spring Boot)

1. Add Dependency

<dependency>
<groupId>de.ferderer.guard4j</groupId>
<artifactId>guard4j-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>

2. Use in Your Code

@RestControllerpublicclassTransferController {
privatestaticfinalEmitterevents = Guard4j.getEmitter(TransferController.class);
@PostMapping("/transfers")
publicTransferResulttransfer(@RequestBodyTransferRequestrequest) {
// Business rule validation with contextif (account.getBalance() < request.getAmount()) {
// Exception handlingthrownewAppException(ErrorCodes.BUSINESS_RULE_VIOLATION)
.withData("rule", "INSUFFICIENT_FUNDS")
.withData("balance", account.getBalance())
.withData("requested", request.getAmount());
}
// Business event observability - generates both metrics and logsevents.info(newTransferInitiatedEvent(request.getUserId(), request.getAmount()));
TransferResultresult = transferService.execute(request);
events.info(newTransferCompletedEvent(result.getTransferId(), result.getStatus()));
returnresult;
}
}
// Simple event definitionpublicrecordTransferInitiatedEvent(StringuserId, BigDecimalamount) implementsObservableEvent {}
publicrecordTransferCompletedEvent(StringtransferId, Stringstatus) implementsObservableEvent {}

3. Get Structured Errors + Automatic Observability

Guard4j automatically provides:

  • Structured error responses that clients can reliably parse
  • Micrometer metrics for error rates, categories, and business impact
  • Structured logging with correlation IDs and business context
  • Framework exception mapping - Spring validation errors become consistent ErrorResponse objects

Framework Support

FrameworkStatusArtifact
Spring Boot 3.x✅ Production Readyguard4j-spring-boot-starter
Quarkus 3.x🛠️ In Active Developmentguard4j-quarkus
Micronaut 4.x🚧 Coming Soonguard4j-micronaut

Custom Error Codes

Create domain-specific error codes for your business logic:

publicenumPaymentErrorCodesimplementsErrorCode {
PAYMENT_GATEWAY_UNAVAILABLE(
HttpStatus.SERVICE_UNAVAILABLE,
Message.of("payment.gateway.unavailable", "Payment gateway temporarily unavailable"),
Severity.CRITICAL,
Category.EXTERNAL
),
DAILY_LIMIT_EXCEEDED(
HttpStatus.UNPROCESSABLE_ENTITY,
Message.of("payment.daily_limit", "Daily payment limit exceeded"),
Severity.WARN,
Category.BUSINESS
);
// Standard ErrorCode implementation...
}
// Usage with business eventspublicclassPaymentService {
privatestaticfinalEmitterevents = Guard4j.getEmitter(PaymentService.class);
publicvoidprocessPayment(Paymentpayment) {
if (exceedsDailyLimit(payment)) {
events.warn(newPaymentLimitExceededEvent(payment.getUserId(), payment.getAmount()));
thrownewAppException(PaymentErrorCodes.DAILY_LIMIT_EXCEEDED)
.withUserId(payment.getUserId())
.withData("amount", payment.getAmount())
.withData("dailyLimit", getDailyLimit(payment.getUserId()));
}
events.info(newPaymentProcessedEvent(payment.getId(), payment.getAmount()));
}
}

Business Event Observability

Guard4j's Emitter Factory pattern provides unified observability for business events:

publicclassLoanProcessorService {
privatestaticfinalEmitterevents = Guard4j.getEmitter(LoanProcessorService.class);
publicvoidprocessLoan(LoanApplicationloan) {
// Replace verbose MeterRegistry + Logger calls with single eventevents.info(newLoanProcessingStartedEvent(loan.getId(), loan.getType()));
try {
LoanDecisiondecision = evaluateRules(loan);
// Business event generates automatic metrics + structured logsevents.info(newLoanProcessedEvent(loan, decision));
} catch (Exceptionex) {
events.error(newLoanProcessingFailedEvent(loan, ex));
throwex;
}
}
}
// Simple event definitionspublicrecordLoanProcessingStartedEvent(StringloanId, StringloanType) implementsObservableEvent {}
publicrecordLoanProcessedEvent(StringloanId, BigDecimalamount, Stringdecision, longprocessingTimeMs)
implementsObservableEvent {
@Overridepublicintmetric() {
return"APPROVED".equals(decision) ? 1 : 0; // Success rate tracking
}
}

Automatic Output:

  • Metrics: guard4j_loan_processed_total{decision="approved", loan_type="mortgage"}
  • Logs: {"level":"INFO","logger":"com.company.LoanProcessorService","event_type":"loan-processed","loan_id":"12345",...}

Architecture

Guard4j follows the Emitter Factory Pattern for clean, type-safe observability:

// Get emitter for your class (cached, thread-safe)privatestaticfinalEmitterevents = Guard4j.getEmitter(MyService.class);
// Emit events with appropriate log levelsevents.info(newBusinessEvent(...)); // Business metrics + INFO logsevents.warn(newWarningEvent(...)); // Alert metrics + WARN logsevents.error(newErrorEvent(...)); // Error metrics + ERROR logs

Key Benefits:

  • Single Event Definition: One record generates both metrics and structured logs
  • Type Safety: Compile-time validation of event structure
  • Logger Correlation: Events use your class logger name for perfect correlation
  • Framework Agnostic: Same API works across Spring Boot, Quarkus, Micronaut

Requirements

  • Java 17+
  • Spring Boot 3.0+ / Quarkus 3.0+ / Micronaut 4.0+

Documentation

Examples

Complete working examples for all supported frameworks:

Roadmap

Current Focus (September 2025)

  • Quarkus Extension development for ReTrust production deployment

Next Steps

  • Finalize Quarkus extension with native compilation support
  • Community feedback and improvements

License

Apache License 2.0 - see LICENSE for details.

Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines.


Why Guard4j? As an independent consultant since 2001 (Java/Spring since 2009), I've seen the same error handling mistakes in enterprise projects across many companies. Guard4j provides the production-grade error handling and observability that Java applications actually need.

About

Production-grade error handling and observability for Java. Framework-agnostic core with Spring Boot, Quarkus, and Micronaut integrations. Type-safe error codes, structured responses, automatic metrics and logging.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages