jMolecules provides a set of Domain-Driven Design (DDD) annotations to model and structure the domain layer of your application. These annotations help enforce the key building blocks of DDD while making the roles of your entities, aggregates, and other components explicit.
The seven core annotations map directly to tactical DDD patterns:
| Annotation | Must Depend On | Must Not Depend On | Represents |
|---|---|---|---|
@AggregateRoot |
@Entity, @ValueObject | Infrastructure or service layers | Root of an aggregate, enforces consistency |
@Entity |
@AggregateRoot, @Entity, @ValueObject | Infrastructure or service layers | Mutable object with identity, part of aggregate |
@ValueObject |
None (pure logic only) | Mutable state or infrastructure | Immutable object defining a domain concept |
@Repository |
@AggregateRoot | Other repositories, services | Abstraction for aggregate persistence |
@Service |
Domain objects, Repositories | Application or infrastructure logic | Stateless domain-specific operations |
@Factory |
@AggregateRoot, @Entity, @ValueObject | Infrastructure logic | Complex domain object creation |
@DomainEvent |
None (pure event data) | Infrastructure logic | Event representing domain significance |
The root of an aggregate — the only entry point for manipulating the aggregate's state. All changes within the aggregate must go through the root to ensure consistency.
@Entity, @ValueObject (domain objects within the aggregate)A mutable object with an identity that is part of an aggregate. Represents a piece of the aggregate that can change over time but is controlled by the aggregate root.
@AggregateRoot, other @Entity, or @ValueObjectAn immutable object that models a concept in the domain. Models values like monetary amounts, coordinates, or dates without tracking identity.
Provides an abstraction for persisting and retrieving aggregates. Hides persistence details and serves as the interface for accessing aggregates.
@AggregateRootA stateless service encapsulating domain-specific operations that don't naturally fit within an entity or value object.
@RepositoryUsed for constructing complex domain objects. Handles creation logic that involves multiple steps or collaborators.
@AggregateRoot, @Entity, or @ValueObjectRepresents a significant occurrence in the domain. Communicates changes to other parts of the system.
@AggregateRoot
class Order(val id: UUID, val customerId: UUID, val items: List<OrderItem>) {
fun calculateTotal(): Money {
return items.fold(Money(0.0)) { total, item -> total.add(item.totalPrice) }
}
fun placeOrder(): OrderPlacedEvent {
return OrderPlacedEvent(id, customerId, calculateTotal())
}
}
@Entity
class OrderItem(val productId: UUID, val quantity: Int, val price: Money) {
val totalPrice: Money
get() = price.multiply(quantity)
}
@ValueObject
data class Money(val amount: Double, val currency: String = "USD") {
fun add(other: Money): Money {
require(currency == other.currency) { "Currencies must match!" }
return Money(amount + other.amount, currency)
}
fun multiply(multiplier: Int): Money {
return Money(amount * multiplier, currency)
}
}
@Repository
interface OrderRepository {
fun save(order: Order)
fun findById(id: UUID): Order?
}
@Service
class OrderService(private val orderRepository: OrderRepository) {
fun placeOrder(order: Order): OrderPlacedEvent {
val event = order.placeOrder()
orderRepository.save(order)
return event
}
}
@DomainEvent
data class OrderPlacedEvent(val orderId: UUID, val customerId: UUID, val total: Money)
Aggregates enforce consistency by restricting direct access to their internal entities and values.
Domain logic remains decoupled from infrastructure, enabling unit tests without external dependencies.
The application aligns with the problem domain, improving clarity and maintainability.
Annotations make roles visible. New developers understand the architecture instantly.
jMolecules DDD annotations provide a structured way to implement Domain-Driven Design principles. By adhering to the constraints, you can maintain a clean separation between your domain logic and infrastructure, ensuring a more robust and scalable system.