### Maven Dependency Setup for jMolecules
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Configure your Maven project to include jMolecules modules. It's recommended to use the jmolecules-bom for centralized version management.
```xml
org.jmolecules
jmolecules-bom
2021.1.0
pom
import
org.jmolecules
jmolecules-ddd
org.jmolecules
jmolecules-events
org.jmolecules
jmolecules-architecture
pom
org.jmolecules
kmolecules-ddd
```
--------------------------------
### Define Custom Stereotype with @Stereotype
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Use the @Stereotype meta-annotation to define custom stereotypes for your application's architectural patterns. This example shows how to define a 'ReadModel' stereotype with specific name, ID, groups, and priority.
```java
import org.jmolecules.stereotype.Stereotype;
import java.lang.annotation.*;
// Define a custom stereotype for your own architectural patterns
@Stereotype(
name = "Read Model",
id = "com.acme.architecture.ReadModel",
groups = { "com.acme.architecture" },
priority = 50
)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ReadModel {}
```
```java
// Alternative: custom stereotype as a marker interface
@Stereotype(
name = "Saga",
id = "com.acme.architecture.Saga",
groups = { "com.acme.architecture" }
)
public interface Saga {}
```
--------------------------------
### Maven Release Perform Command
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Perform the release after preparation using Maven's release plugin, specifying the GPG key name for signing.
```bash
mvn release:perform -Dgpg.keyname=$keyname
```
--------------------------------
### Maven Release Prepare Command
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Prepare for a release using Maven's release plugin, specifying commit messages for SCM changes.
```bash
mvn release:prepare -DscmReleaseCommitComment="$ticketId - Release version $version." -DscmDevelopmentCommitComment="$ticketId - Prepare next development iteration."
```
--------------------------------
### Define Bounded Context with @BoundedContext
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Package-level annotation to identify bounded contexts. Supports optional id, name, and description attributes for documentation generation. Requires BoundedContext import.
```java
// com/acme/banking/package-info.java
@BoundedContext(
id = "com.acme.banking",
name = "Banking",
description = "Manages bank accounts, transfers, and transaction history"
)
package com.acme.banking;
import org.jmolecules.ddd.annotation.BoundedContext;
```
--------------------------------
### Define Module with @Module
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Package-level annotation to identify DDD modules. Supports optional id, name, and description attributes for documentation generation. Requires Module import.
```java
// com/acme/banking/accounts/package-info.java
@Module(
id = "accounts",
name = "Accounts Module",
description = "Core account management and lifecycle"
)
package com.acme.banking.accounts;
import org.jmolecules.ddd.annotation.Module;
```
--------------------------------
### Onion Architecture Annotations (Classical and Simplified)
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Supports two variants of Onion Architecture: classical (4 rings) and simplified (3 rings). Annotate packages to define the rings of your architecture.
```java
// === Classical (4-ring) Onion Architecture ===
import org.jmolecules.architecture.onion.classical.*;
// Innermost ring — pure domain model, no outward dependencies
@DomainModelRing
package com.acme.banking.domain.model;
```
```java
// Domain services ring — depends only on DomainModelRing
@DomainServiceRing
package com.acme.banking.domain.services;
```
```java
// Application services ring — orchestrates domain services
@ApplicationServiceRing
package com.acme.banking.application;
```
```java
// Outermost ring — infrastructure, adapters, frameworks
@InfrastructureRing
package com.acme.banking.infrastructure;
```
```java
// === Simplified (3-ring) Onion Architecture ===
import org.jmolecules.architecture.onion.simplified.*;
// Combined domain model + services ring
@DomainRing
package com.acme.banking.domain;
```
```java
// Application ring
@ApplicationRing
package com.acme.banking.app;
```
```java
// Infrastructure ring
@InfrastructureRing
package com.acme.banking.infra;
```
--------------------------------
### Kotlin DDD Annotations for Aggregate Root and Value Objects
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Demonstrates Kotlin DDD patterns using kmolecules annotations. Ensure correct data classes and value object definitions for immutability and validation.
```kotlin
import org.jmolecules.ddd.annotation.AggregateRoot
import org.jmolecules.ddd.annotation.Entity
import org.jmolecules.ddd.annotation.Identity
import org.jmolecules.ddd.annotation.ValueObject
import org.jmolecules.ddd.annotation.Repository
// Kotlin aggregate root using kmolecules annotations
@AggregateRoot
data class BankAccount(
@Identity val iban: IBAN,
var balance: Money
) {
private val _entries: MutableList = mutableListOf()
val entries: List get() = _entries.toList()
fun credit(amount: Money): BankAccount {
require(amount.currency == balance.currency) { "Currency mismatch" }
_entries += AccountEntry(amount = amount, type = EntryType.CREDIT)
return copy(balance = balance + amount)
}
}
```
```kotlin
@ValueObject
@JvmInline
value class IBAN(val value: String) {
init { require(value.matches(Regex("[A-Z]{2}[0-9]{2}[A-Z0-9]{4,30}"))) }
}
```
```kotlin
@ValueObject
data class Money(val amount: BigDecimal, val currency: String) {
operator fun plus(other: Money): Money {
require(currency == other.currency) { "Currency mismatch" }
return Money(amount + other.amount, currency)
}
}
```
```kotlin
@Entity
data class AccountEntry(
@Identity val id: UUID = UUID.randomUUID(),
val amount: Money,
val type: EntryType
)
```
```kotlin
@Repository
class AccountRepository {
private val store = mutableMapOf()
fun save(account: BankAccount) { store[account.iban] = account }
fun findByIban(iban: IBAN): BankAccount? = store[iban]
}
```
--------------------------------
### CQRS Command and Query Model Annotations in Java
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Defines commands and query models using Jmolecules annotations for CQRS. Ensure the correct namespace and command/query names are used.
```java
import org.jmolecules.architecture.cqrs.*;
// Commands — imperative requests for state change
@Command(namespace = "com.acme.banking", name = "TransferMoney")
record TransferMoneyCommand(UUID transferId, String fromIban, String toIban, BigDecimal amount) {}
@Command(namespace = "com.acme.banking", name = "OpenAccount")
record OpenAccountCommand(String iban, BigDecimal initialDeposit, String currency) {}
// Query model — read-optimized projection (only used in the Query side)
@QueryModel
class AccountSummaryView {
private final String iban;
private BigDecimal balance;
private int transactionCount;
AccountSummaryView(String iban, BigDecimal balance) {
this.iban = iban;
this.balance = balance;
}
void applyCredit(BigDecimal amount) {
balance = balance.add(amount);
transactionCount++;
}
// getters...
}
```
```java
// Command handler — processes commands, may reject them
class BankingCommandHandler {
private final AccountRepository repository;
@CommandHandler(namespace = "com.acme.banking", name = "OpenAccount")
AccountId handle(OpenAccountCommand cmd) {
Account account = Account.open(
new AccountId(UUID.randomUUID()),
cmd.iban(),
new Money(cmd.initialDeposit(), cmd.currency())
);
repository.save(account);
return account.getId();
}
@CommandHandler(namespace = "com.acme.banking", name = "TransferMoney")
void handle(TransferMoneyCommand cmd) {
// business logic — may throw to reject the command
Account source = repository.findByIban(cmd.fromIban())
.orElseThrow(() -> new IllegalArgumentException("Source account not found"));
source.debit(new Money(cmd.amount(), "EUR"));
repository.save(source);
}
}
```
--------------------------------
### Annotate Domain Layer Package
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Annotate the package-info.java file to mark an entire package as the Domain Layer using jMolecules architecture annotations.
```java
@DomainLayer
package org.acmebank.domain;
import org.jmolecules.architecture.layered.*;
```
--------------------------------
### Annotate Application Layer Package
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Annotate the package-info.java file to mark an entire package as the Application Layer using jMolecules architecture annotations.
```java
@ApplicationLayer
package org.acmebank.application;
import org.jmolecules.architecture.layered.*;
```
--------------------------------
### Hexagonal Architecture Annotations
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Annotations for Ports & Adapters / Hexagonal Architecture. Use @Application for the core, @PrimaryPort/@SecondaryPort for boundary interfaces, and @PrimaryAdapter/@SecondaryAdapter for implementations.
```java
import org.jmolecules.architecture.hexagonal.*;
// Core application — must only use Ports, never Adapters
@Application
package com.acme.banking.core;
```
```java
// Primary port — interface driven by the outside world (e.g., REST, CLI)
@PrimaryPort(name = "AccountManagement", description = "Use cases for managing bank accounts")
interface AccountManagementPort {
AccountId openAccount(String iban, BigDecimal initialDeposit);
void credit(AccountId id, BigDecimal amount);
Optional findAccount(AccountId id);
}
```
```java
// Primary adapter — connects HTTP to the core via the primary port
@PrimaryAdapter(name = "REST API", description = "HTTP REST adapter for account management")
class AccountRestAdapter {
private final AccountManagementPort port;
AccountRestAdapter(AccountManagementPort port) { this.port = port; }
// e.g., maps HTTP request -> port call -> HTTP response
AccountView handleGet(String iban) {
return port.findAccount(new AccountId(UUID.fromString(iban)))
.orElseThrow(() -> new NoSuchElementException("Account not found"));
}
}
```
```java
// Secondary port — abstraction the core defines, infrastructure implements
@SecondaryPort(name = "AccountRepository", description = "Persistence abstraction for accounts")
interface AccountRepository {
void save(Account account);
Optional findById(AccountId id);
}
```
```java
// Secondary adapter — implements the secondary port using a specific technology
@SecondaryAdapter(name = "JPA Account Repository", description = "JPA-based persistence")
class JpaAccountRepository implements AccountRepository {
// JPA EntityManager, etc.
@Override public void save(Account account) { /* JPA save logic */ }
@Override public Optional findById(AccountId id) { /* JPA find logic */ return Optional.empty(); }
}
```
--------------------------------
### Layered Architecture Annotations
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Use these annotations to mark packages or types with classic architectural layers. Apply to package-info.java for package-wide inheritance or directly to classes.
```java
// com/acme/banking/domain/package-info.java
@DomainLayer
package com.acme.banking.domain;
import org.jmolecules.architecture.layered.DomainLayer;
```
```java
// com/acme/banking/application/package-info.java
@ApplicationLayer
package com.acme.banking.application;
import org.jmolecules.architecture.layered.ApplicationLayer;
```
```java
// com/acme/banking/infrastructure/package-info.java
@InfrastructureLayer
package com.acme.banking.infrastructure;
import org.jmolecules.architecture.layered.InfrastructureLayer;
```
```java
// com/acme/banking/interfaces/package-info.java
@InterfaceLayer
package com.acme.banking.interfaces;
import org.jmolecules.architecture.layered.InterfaceLayer;
```
```java
// Alternatively, annotate individual classes when mixing layers in one package
import org.jmolecules.architecture.layered.*;
import org.jmolecules.ddd.annotation.*;
@DomainLayer
@AggregateRoot
public class BankAccount { /* ... */ }
```
```java
@ApplicationLayer
@Service
public class TransferMoney { /* ... */ }
```
```java
@InfrastructureLayer
@Repository
public class JpaBankAccountRepository { /* ... */ }
```
```java
@InterfaceLayer
public class AccountRestController { /* ... */ }
```
--------------------------------
### DDD Type-Based Model with Interfaces
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Leverage the Java type system with interfaces for compile-time verification of DDD structural constraints. Dedicated identifier types prevent accidental mixing.
```java
import org.jmolecules.ddd.types.*;
// Dedicated identifier types per aggregate prevent mixing
record AccountId(UUID value) implements Identifier {}
record CustomerId(UUID value) implements Identifier {}
// Aggregate root — self-referential generic type T
class Account implements AggregateRoot {
private final AccountId id;
private MonetaryAmount balance;
private final List entries = new ArrayList<>();
Account(AccountId id, MonetaryAmount initialBalance) {
this.id = id;
this.balance = initialBalance;
}
@Override
public AccountId getId() { return id; }
void credit(MonetaryAmount amount) {
balance = balance.add(amount);
entries.add(new AccountEntry(this, amount, EntryType.CREDIT));
}
}
// Entity — belongs to Account aggregate, cannot be confused with another aggregate's entity
class AccountEntry implements Entity {
private final UUID id = UUID.randomUUID();
private final MonetaryAmount amount;
private final EntryType type;
AccountEntry(Account owner, MonetaryAmount amount, EntryType type) {
this.amount = amount; this.type = type;
}
@Override
public UUID getId() { return id; }
}
// Repository typed to the aggregate root and its identifier
class Accounts implements Repository {
private final Map store = new ConcurrentHashMap<>();
void save(Account account) { store.put(account.getId(), account); }
Optional findById(AccountId id) {
return Optional.ofNullable(store.get(id));
}
}
// Value objects implement ValueObject (marker interface)
record Money(BigDecimal amount, String currency) implements ValueObject {
Money add(Money other) {
if (!currency.equals(other.currency)) throw new IllegalArgumentException("Currency mismatch");
return new Money(amount.add(other.amount), currency);
}
}
```
--------------------------------
### Create Associations with `Association.forAggregate()` and `Association.forId()`
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Use `Association.forAggregate()` to create a reference from an aggregate instance and `Association.forId()` to create one from a raw identifier. These factory methods ensure type-safe cross-aggregate references that hold only an identifier.
```java
import org.jmolecules.ddd.types.*;
record OrderId(UUID value) implements Identifier {}
record ProductId(UUID value) implements Identifier {}
class Order implements AggregateRoot {
private final OrderId id;
// Cross-aggregate reference to Product — only holds the ID
private final Association product;
Order(OrderId id, Product product) {
this.id = id;
// Create association from an aggregate instance
this.product = Association.forAggregate(product);
}
Order(OrderId id, ProductId productId) {
this.id = id;
// Create association from a raw identifier
this.product = Association.forId(productId);
}
@Override
public OrderId getId() { return id; }
// Check if order references a specific product
boolean refersTo(Product p) {
return product.pointsTo(p); // by aggregate instance
}
boolean refersToId(ProductId pid) {
return product.pointsTo(pid); // by identifier
}
boolean refersSameProductAs(Order other) {
return product.pointsToSameAggregateAs(other.product); // cross-instance check
}
}
class Product implements AggregateRoot {
private final ProductId id;
Product(ProductId id) { this.id = id; }
@Override public ProductId getId() { return id; }
}
// Usage
ProductId pid = new ProductId(UUID.randomUUID());
Product product = new Product(pid);
Order order = new Order(new OrderId(UUID.randomUUID()), product);
assert order.refersTo(product); // true
assert order.refersToId(pid); // true
```
--------------------------------
### Annotate Classes with Layered Architecture
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Annotate classes directly to define their layer within the architecture. Supports Domain, Application, Infrastructure, and Interface layers.
```java
import org.jmolecules.architecture.layered.*;
@DomainLayer
@Entity
public class BankAccount { /* ... */ }
@ApplicationLayer
@Service
public class TransferMoney { /* ... */ }
```
--------------------------------
### Declare Domain Events with `@DomainEvent` annotation or `DomainEvent` interface
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Use either the `@DomainEvent` annotation or implement the `DomainEvent` interface to declare a class as a domain event. Optional `namespace` and `name` attributes provide stable external identifiers.
```java
import org.jmolecules.event.annotation.DomainEvent;
import org.jmolecules.event.annotation.DomainEventPublisher;
import org.jmolecules.event.annotation.DomainEventHandler;
import org.jmolecules.event.annotation.Externalized;
// Annotation-based domain event
@DomainEvent(namespace = "com.acme.banking", name = "AccountCredited")
record AccountCredited(IBAN iban, MonetaryAmount amount, Instant occurredAt) {}
// Type-based domain event (implements marker interface)
record AccountDebited(IBAN iban, MonetaryAmount amount, Instant occurredAt)
implements org.jmolecules.event.types.DomainEvent {}
// Event to be published externally (e.g., to a message broker)
@DomainEvent(namespace = "com.acme.banking", name = "TransferCompleted")
@Externalized(target = "banking.transfers.completed") // logical target topic/channel
record TransferCompleted(UUID transferId, IBAN from, IBAN to, MonetaryAmount amount) {}
// Service publishing events
class AccountService {
private final ApplicationEventPublisher publisher;
AccountService(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@DomainEventPublisher(
publishes = "com.acme.banking.AccountCredited",
type = DomainEventPublisher.PublisherType.INTERNAL
)
void credit(IBAN iban, MonetaryAmount amount) {
// ... business logic ...
publisher.publishEvent(new AccountCredited(iban, amount, Instant.now()));
}
}
// Event handler with explicit namespace/name linkage
class AuditService {
@DomainEventHandler(
namespace = "com.acme.banking",
name = "AccountCredited"
)
void on(AccountCredited event) {
// Audit log, projections, etc.
System.out.printf("Account %s credited with %s at %s%n",
event.iban(), event.amount(), event.occurredAt());
}
// Wildcard: handle ALL events in the namespace
@DomainEventHandler(namespace = "com.acme.banking", name = "*")
void onAnyBankingEvent(Object event) {
System.out.println("Banking event received: " + event.getClass().getSimpleName());
}
}
```
--------------------------------
### Tooling Detection of @Stereotype
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Any type annotated with @Stereotype, directly or transitively, will be detected by various architectural tooling. This enables automated verification and documentation of architectural rules.
```java
// Tooling detection: any type annotated with @Stereotype (directly or transitively)
// will be detected by ArchUnit rules, jQAssistant, Spring Modulith, etc.
```
--------------------------------
### Express DDD Entity with Annotations
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Use jMolecules DDD annotations to mark classes as DDD building blocks like Entity, Identity, ValueObject, and Repository.
```java
import org.jmolecules.ddd.annotation.*;
@Entity
class BankAccount {
@Identity
final IBAN iban;
/* ... */
}
@ValueObject
class IBAN { /* ... */ }
@ValueObject
record Currency { /* ... */ }
@Repository
class Accounts { /* ... */ }
```
--------------------------------
### Gradle Dependency for jMolecules DDD
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Include the jMolecules DDD artifact in your Gradle project's dependencies. Ensure mavenCentral() is configured in your repositories.
```groovy
repositories {
mavenCentral()
}
dependencies {
implementation("org.jmolecules:jmolecules-ddd:1.9.0")
}
```
--------------------------------
### Define Custom Stereotype Interface
Source: https://github.com/xmolecules/jmolecules/wiki/The-Stereotype-Metamodel
Define a custom stereotype as an interface using the @Stereotype meta-annotation. This allows classes to implement the stereotype.
```java
package com.acme.example.stereotypes;
@org.jmolecules.Stereotype
public interface MyCustomStereotype { … }
```
--------------------------------
### Assign Custom Stereotype to Application Component
Source: https://github.com/xmolecules/jmolecules/wiki/The-Stereotype-Metamodel
Assign a custom stereotype to an application component by either annotating it with the custom stereotype annotation or having it implement the custom stereotype interface.
```java
@com.acme.example.stereotypes.MyCustomStereotype // <- either or …
class MyApplicationComponent implements MyCustomStereotype { … }
```
--------------------------------
### Cross-Aggregate Reference with @Association
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Use `@Association` to express cross-aggregate references by identifier. The `aggregateType` attribute provides explicit tooling metadata.
```java
import org.jmolecules.ddd.annotation.*;
@AggregateRoot
class Transfer {
@Identity
private final UUID id = UUID.randomUUID();
// Cross-aggregate references via @Association — no direct object reference
@Association(aggregateType = BankAccount.class)
private final IBAN sourceIban;
@Association(aggregateType = BankAccount.class)
private final IBAN targetIban;
private final MonetaryAmount amount;
Transfer(IBAN sourceIban, IBAN targetIban, MonetaryAmount amount) {
this.sourceIban = sourceIban;
this.targetIban = targetIban;
this.amount = amount;
}
}
```
--------------------------------
### Apply Custom Stereotypes
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Apply custom stereotypes, such as the defined '@ReadModel' and 'Saga', to your classes. These custom stereotypes can be used alongside jMolecules built-in annotations.
```java
// Apply custom stereotypes — usable alongside jMolecules built-ins
@ReadModel
class AccountProjection {
private String iban;
private BigDecimal balance;
// Updated by event handlers; exposes read-optimized fields
}
```
```java
class PaymentSaga implements Saga {
// Coordinates multi-step payment flow spanning multiple aggregates
}
```
--------------------------------
### Define Aggregate Root with @AggregateRoot
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Marks the root entity of a DDD aggregate. Changes within one aggregate are strongly consistent; cross-aggregate references use identifiers only. Requires imports for DDD annotations.
```java
import org.jmolecules.ddd.annotation.*;
// package-info.java in the banking domain
@BoundedContext(name = "Banking", description = "Core banking operations")
package com.acme.banking;
// Clean domain class — no "Entity" or "AggregateRoot" suffix needed
@AggregateRoot
class BankAccount {
@Identity
final IBAN iban;
private MonetaryAmount balance;
private List transactions = new ArrayList<>();
BankAccount(IBAN iban, MonetaryAmount initialBalance) {
this.iban = iban;
this.balance = initialBalance;
}
void deposit(MonetaryAmount amount) {
this.balance = balance.add(amount);
this.transactions.add(Transaction.credit(amount));
}
IBAN getIban() { return iban; }
MonetaryAmount getBalance() { return balance; }
}
@ValueObject
record IBAN(String value) {
IBAN {
if (value == null || !value.matches("[A-Z]{2}[0-9]{2}[A-Z0-9]{4,30}"))
throw new IllegalArgumentException("Invalid IBAN: " + value);
}
}
@ValueObject
record MonetaryAmount(BigDecimal amount, Currency currency) {
MonetaryAmount add(MonetaryAmount other) {
if (!currency.equals(other.currency))
throw new IllegalArgumentException("Currency mismatch");
return new MonetaryAmount(amount.add(other.amount), currency);
}
}
@Entity
class Transaction {
@Identity
final UUID id = UUID.randomUUID();
final MonetaryAmount amount;
final TransactionType type;
private Transaction(MonetaryAmount amount, TransactionType type) {
this.amount = amount; this.type = type;
}
static Transaction credit(MonetaryAmount amount) {
return new Transaction(amount, TransactionType.CREDIT);
}
}
@Repository
class Accounts {
private final Map store = new ConcurrentHashMap<>();
void save(BankAccount account) { store.put(account.getIban(), account); }
Optional findByIban(IBAN iban) {
return Optional.ofNullable(store.get(iban));
}
}
@Service
class MoneyTransferService {
private final Accounts accounts;
void transfer(IBAN from, IBAN to, MonetaryAmount amount) {
BankAccount source = accounts.findByIban(from)
.orElseThrow(() -> new IllegalArgumentException("Account not found: " + from));
// ... debit source, credit target
accounts.save(source);
}
}
@Factory
class BankAccountFactory {
BankAccount openAccount(String rawIban, BigDecimal initialDeposit) {
return new BankAccount(new IBAN(rawIban),
new MonetaryAmount(initialDeposit, Currency.getInstance("EUR")));
}
}
```
--------------------------------
### Maven Dependency for jMolecules DDD
Source: https://github.com/xmolecules/jmolecules/blob/main/readme.adoc
Add the jMolecules DDD artifact as a Maven dependency to include its core functionalities in your project.
```xml
org.jmolecules
jmolecules-ddd
1.9.0
```
--------------------------------
### Define Custom Stereotype Annotation
Source: https://github.com/xmolecules/jmolecules/wiki/The-Stereotype-Metamodel
Use the @Stereotype meta-annotation to define a custom stereotype as an annotation. This allows it to be applied to classes, interfaces, or methods.
```java
package com.acme.example.stereotypes;
@org.jmolecules.Stereotype
@Retention(RUNTIME)
public @interface MyCustomStereotype { … }
```
--------------------------------
### Mark Identity with @Identity
Source: https://context7.com/xmolecules/jmolecules/llms.txt
Marks a field or getter as the identity of an @AggregateRoot or @Entity. Used by integration tooling to map to primary keys. Requires DDD annotation imports.
```java
import org.jmolecules.ddd.annotation.*;
@AggregateRoot
class Order {
// Field-level identity
@Identity
private final OrderId id;
@ValueObject
record OrderId(UUID value) {
static OrderId generate() { return new OrderId(UUID.randomUUID()); }
}
Order() {
this.id = OrderId.generate();
}
OrderId getId() { return id; }
}
@Entity
class OrderLine {
// Method-level identity
private final UUID lineId = UUID.randomUUID();
@Identity
UUID getLineId() { return lineId; }
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.