A lightweight, type-safe Java library for dependency inversion and inversion of control.
Contracts provides a modern approach to decoupling API definitions from their implementations using a Contract-based system. This library enables clean architecture by separating what you need (the contract) from how it's provided (the implementation), without requiring reflection, annotations, or dependency injection frameworks.
- Type-Safe Contracts: Generic-based contracts eliminate casting and provide compile-time safety
- Zero Reflection: No reflection, annotations, or bytecode manipulation required
- Java Module System: Full JPMS support with strong encapsulation
- Lifecycle Management: Built-in reference counting and resource management
- Framework Agnostic: Works standalone or alongside Spring Boot, Guice, or other DI frameworks
- SOLID Principles: Designed around dependency inversion, interface segregation, and single responsibility
- Security Focused: OpenSSF Best Practices compliant with contract-level access control
- Multi-Module Architecture: Clean separation between API (
contracts-api), implementation (contracts-impl), and testing (contracts-test)
The Contract pattern has three simple steps:
Define a contract as a unique key that represents an agreement between providers and consumers:
// Define a contract for a service - each contract is a unique key
public static final Contract<WeatherService> WEATHER_SERVICE =
Contract.create("WeatherService");A provider binds an implementation to the contract using a Promisor:
// Bind an implementation to the contract
GlobalContracts.bindContract(WEATHER_SERVICE, () -> new WeatherServiceImpl());
// Or with a singleton pattern
GlobalContracts.bindContract(WEATHER_SERVICE,
GlobalContracts.singleton(() -> new WeatherServiceImpl()));Consumers claim the implementation through the contract:
// Claim the implementation - type-safe, no casting needed
WeatherService service = GlobalContracts.claimContract(WEATHER_SERVICE);
String forecast = service.getForecast();A Contract<T> is a unique key that establishes an agreement between a provider (who binds) and a consumer (who claims). Each contract instance is unique by identity, ensuring proper encapsulation.
A Promisor<T> is a functional interface that provides the implementation. It supports:
- Simple factories: Return a new instance on each claim
- Singletons: Return the same instance (via
GlobalContracts.singleton()) - Lifecycle management: Reference-counted resources (via
GlobalContracts.lifeCycle())
- GlobalContracts: Singleton instance for application-wide contracts
- Contracts.createContracts(): Create isolated contract repositories for testing or modularity
// Lifecycle-managed promisor with automatic open/close
Promisor<Database> dbPromisor = GlobalContracts.lifeCycle(() -> new Database());
AutoClose unbind = GlobalContracts.bindContract(DB_CONTRACT, dbPromisor);
// When done, unbind to decrement reference count
unbind.close();// Create a contract with custom configuration
Contract<Service> contract = Contract.create(Service.class, builder -> {
builder.name("MyService")
.replaceable(true); // Allow rebinding
});Create contract repositories that delegate to parent repositories for shared contracts.
The library is organized into multiple Gradle submodules:
contracts-api: Core API interfaces and contracts (no dependencies)contracts-impl: Default implementation of the Contracts systemcontracts-test: Reusable test utilities for testing contract-based codecontracts-smoke: Smoke tests for validation- Root module: Aggregates API and implementation for easy consumption
dependencies {
implementation 'io.github.jonloucks.contracts:contracts:2.5.2'
}<dependency>
<groupId>io.github.jonloucks.contracts</groupId>
<artifactId>contracts</artifactId>
<version>2.5.2</version>
</dependency>- Plugin Architectures: Define extension points without tight coupling
- Testing: Easily mock dependencies by binding test implementations
- Modular Applications: Decouple modules using contracts as boundaries
- Library Development: Provide APIs without exposing implementations
- Configuration Management: Bind different implementations based on environment
- Javadoc API Documentation
- Test Coverage Report
- License
- Contributing Guidelines
- Code of Conduct
- Coding Standards
- Security Policy
- Pull Request Template
- Deployment: Java 11+ (LTS)
- Compilation: Java 9+ language level
- Module System: Full JPMS support
The library adheres to these core principles:
- SOLID Principles: Dependency inversion, interface segregation, single responsibility
- Security First: OpenSSF Best Practices with contract-level access control
- Strong Encapsulation: Proper data hiding and module boundaries
- Universal Compatibility: Use anywhere, anytime across many codebases
- Type Safety: No casting needed, no unchecked surprises
- Privacy by Default: Contracts are only visible to the author unless explicitly shared
- LTS Support: Deploys on oldest supported LTS Java version (currently 11) with JPMS
- Minimal Language Requirements: Compiles with Java 9 language level
- Zero Magic: No reflection, injection, or annotations required
- Testability: Promotes black-box testing, leading to test reuse and maintainability
- Framework Neutral: Works standalone or with Spring Boot, Guice, etc.
Traditional dependency injection frameworks often require:
- Reflection and runtime classpath scanning
- Framework-specific annotations
- Complex configuration
- Tight coupling to the DI container
Contracts offers a simpler alternative:
- ✅ Compile-time type safety
- ✅ Explicit, readable code
- ✅ No framework lock-in
- ✅ Works with Java modules
- ✅ Zero runtime overhead from reflection
- ✅ Perfect for libraries that need to avoid DI framework dependencies
# Build the project
./gradlew build
# Run all tests with coverage
./gradlew check jacocoTestReport
# Publish to local Maven repository
./gradlew publishToMavenLocalSee LICENSE.md for details.
Contributions are welcome! Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md before submitting pull requests.