Contracts

Java Dependency Contracts for dependency inversion

View the Project on GitHub jonloucks/contracts

Contracts

A lightweight, type-safe Java library for dependency inversion and inversion of control.

Overview

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.

Key Features

Quick Start

The Contract pattern has three simple steps:

1. Author a Contract

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");

2. Bind (Promise) an Implementation

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()));

3. Claim (Consume) the Implementation

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();

Core Concepts

Contracts

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.

Promisors

A Promisor<T> is a functional interface that provides the implementation. It supports:

Global vs Local Contracts

Reference Counting & Lifecycle Management

// 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();

Contract Configuration

// Create a contract with custom configuration
Contract<Service> contract = Contract.create(Service.class, builder -> {
    builder.name("MyService")
           .replaceable(true);  // Allow rebinding
});

Partners (Aggregated Contracts)

Create contract repositories that delegate to parent repositories for shared contracts.

Project Structure

The library is organized into multiple Gradle submodules:

Installation

Gradle

dependencies {
    implementation 'io.github.jonloucks.contracts:contracts:2.5.2'
}

Maven

<dependency>
    <groupId>io.github.jonloucks.contracts</groupId>
    <artifactId>contracts</artifactId>
    <version>2.5.2</version>
</dependency>

Use Cases

Badges

OpenSSF Best Practices Coverage Badge Javadoc Badge

Requirements

Design Principles

The library adheres to these core principles:

  1. SOLID Principles: Dependency inversion, interface segregation, single responsibility
  2. Security First: OpenSSF Best Practices with contract-level access control
  3. Strong Encapsulation: Proper data hiding and module boundaries
  4. Universal Compatibility: Use anywhere, anytime across many codebases
  5. Type Safety: No casting needed, no unchecked surprises
  6. Privacy by Default: Contracts are only visible to the author unless explicitly shared
  7. LTS Support: Deploys on oldest supported LTS Java version (currently 11) with JPMS
  8. Minimal Language Requirements: Compiles with Java 9 language level
  9. Zero Magic: No reflection, injection, or annotations required
  10. Testability: Promotes black-box testing, leading to test reuse and maintainability
  11. Framework Neutral: Works standalone or with Spring Boot, Guice, etc.

Why Contracts?

Traditional dependency injection frameworks often require:

Contracts offers a simpler alternative:

Building from Source

# Build the project
./gradlew build

# Run all tests with coverage
./gradlew check jacocoTestReport

# Publish to local Maven repository
./gradlew publishToMavenLocal

License

See LICENSE.md for details.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md before submitting pull requests.