A comprehensive shared kernel library implementing Domain-Driven Design (DDD) patterns and hexagonal architecture principles for Java applications.
This implementation is part of a comprehensive exploration of Hexagonal Architecture patterns. The concepts are covered in depth in:
English Version Decoupling by Design: A Pragmatic Approach to Hexagonal Architecture
VersiΓ³n en EspaΓ±ol
Desacoplamiento por DiseΓ±o: Una GuΓa PrΓ‘ctica para la Arquitectura Hexagonal
The book provides in-depth coverage of:
- Shared kernel implementation strategies
- Command and Query pattern variations
- Domain modeling with value objects and entities
- Specification pattern for business rules
- Transaction management in hexagonal systems
- Evolutionary architecture approaches
- Java: Upgraded from JDK 21 β JDK 25 (GA release)
- Maven Compiler Plugin: 3.12.1 β 3.14.1
- Versions Maven Plugin: 2.17.1 β 2.20.1
- JUnit Jupiter: RELEASE β 6.0.2 (fixed anti-pattern)
- SLF4J API: 2.0.17 (latest GA)
- Vavr: 0.11.0 (latest stable)
- Centralized Properties: All versions managed in root POM
- Provided Scope Strategy: SLF4J and Vavr use
providedscope to avoid version conflicts - Consumer Flexibility: Projects using this library can choose their own logging and functional programming library versions
- 90%+ Test Coverage: Added extensive unit tests for all non-interface/annotation classes
- Modern Testing: JUnit 5, AssertJ, parameterized tests
- Quality Assurance: Timer precision tests, specification logic validation, decorator pattern verification
Base classes and annotations for Domain-Driven Design:
- Entities & Value Objects: Type-safe domain modeling
- Aggregate Roots: DDD aggregate pattern implementation
- Repositories: Domain repository contracts
- Domain Services: Business logic encapsulation
- Identities: Strongly-typed identifiers
CQRS command handling with decorator support:
- Command Interface: Base command contract
- Command Bus: Decoupled command execution
- Either Bus: Functional error handling with Vavr
- Logging Decorator: Execution timing and logging
- Extensible: Easy to add custom decorators
CQRS query handling with decorator support:
- Query Interface: Base query contract
- Query Bus: Decoupled query execution
- Either Bus: Functional error handling with Vavr
- Logging Decorator: Execution timing and logging
- Extensible: Easy to add custom decorators
Flexible business rule composition:
- Specification Pattern: Encapsulated business rules
- Fluent API: Chainable logical operations (
and,or,not) - Composite Operations: Complex rule combinations
- Type Safety: Generic type support
Technology-agnostic transaction boundaries:
- @Transactional: Framework-independent annotation
- Isolation Levels: Configurable isolation
- Propagation: Transaction propagation control
<dependency>
<groupId>io.github.emedina</groupId>
<artifactId>shared-kernel-domain</artifactId>
<version>1.0.0</version>
</dependency>When using modules with provided dependencies, add these to your project:
<!-- For command-bus, query-bus, command-either-bus, query-either-bus -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
</dependency>
<!-- For command-either-bus only -->
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.11.0</version>
</dependency>
<!-- Logging implementation (choose one) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>@ValueObject
public class Email implements ValueObject<Email> {
private final String value;
public Email(String value) {
if (!isValid(value)) {
throw new IllegalArgumentException("Invalid email format");
}
this.value = value;
}
@Override
public boolean sameValueAs(Email other) {
return Objects.equals(this.value, other.value);
}
private boolean isValid(String email) {
return email != null && email.contains("@");
}
}// Command
public class CreateUserCommand implements Command {
private final String email;
private final String name;
// constructors, getters...
}
// Handler
@Component
public class CreateUserHandler implements CommandHandler<CreateUserCommand> {
@Override
public void handle(CreateUserCommand command) {
// Implementation
}
}
// Usage
@Service
public class UserService {
private final CommandBus commandBus;
public void createUser(String email, String name) {
commandBus.execute(new CreateUserCommand(email, name));
}
}// Business rules
Specification<User> activeUser = user -> user.isActive();
Specification<User> premiumUser = user -> user.isPremium();
Specification<User> recentLogin = user -> user.getLastLogin().isAfter(LocalDate.now().minusDays(30));
// Compose complex rules
Specification<User> eligibleForOffer = activeUser
.and(premiumUser.or(recentLogin))
.andNot(user -> user.hasActiveOffer());
// Use in domain logic
if (eligibleForOffer.isSatisfiedBy(user)) {
// Send offer
}- Ports & Adapters: Clear separation of concerns
- Domain Isolation: Business logic independent of frameworks
- Dependency Inversion: Dependencies point inward
- Ubiquitous Language: Shared vocabulary between domain experts and developers
- Bounded Contexts: Clear module boundaries
- Strategic Design: Aggregate, Entity, Value Object patterns
- Command Side: State-changing operations
- Query Side: Data retrieval operations
- Separation: Different models for reads and writes
- JDK 25 or higher
- Maven 3.9+
mvn clean compilemvn testmvn versions:display-dependency-updates
mvn versions:display-plugin-updates| Shared Kernel | Min JDK | SLF4J API | Vavr | Notes |
|---|---|---|---|---|
| 1.0.x | 25 | 2.0.0+ | 0.11.0+ | Current |
- Code Style: Follow existing patterns and conventions
- Testing: Maintain 90%+ test coverage
- Documentation: Update README for significant changes
- Dependencies: Use only GA releases, avoid alpha/beta/snapshots
This project is licensed under the MIT License - see the LICENSE file for details.
hexagonal-architecture domain-driven-design ddd cqrs java maven specifications command-pattern value-objects shared-kernel