Java Dependency Contracts for dependency inversion
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.
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:
GlobalContracts.singleton())GlobalContracts.lifeCycle())// 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 validationdependencies {
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>
The library adheres to these core principles:
Traditional dependency injection frameworks often require:
Contracts offers a simpler alternative:
# Build the project
./gradlew build
# Run all tests with coverage
./gradlew check jacocoTestReport
# Publish to local Maven repository
./gradlew publishToMavenLocal
See LICENSE.md for details.
Contributions are welcome! Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md before submitting pull requests.