Boost Java Backend Development with DDD, CQRS, and Automated Maven Archetype Generation
This article explains how to lower the learning curve of DDD and CQRS by using structured, standardized, and templated approaches, introduces a Maven archetype for rapid project scaffolding, and demonstrates an IntelliJ IDEA plugin that auto‑generates boilerplate code for aggregate roots, commands, queries, and related components.
1. Background
Domain‑Driven Design (DDD) is known for its high entry barrier, introducing many abstract concepts such as entities, value objects, domain services, aggregates, factories, repositories, and application services. Newcomers often feel overwhelmed, especially when additional patterns like CQRS, hexagonal architecture, adapters, and anti‑corruption layers are added.
The author reflects on the difficulty of mastering these concepts individually and the challenge of aligning an entire team.
2. Purpose
The goals are to:
Reduce the memory cost of concepts so junior developers are not intimidated by DDD.
Unify standards so business processes and component designs remain consistent across the team.
Improve development efficiency by letting machines handle repetitive logic.
3. Feature Overview
3.1 Maven Archetype
The Maven archetype creates a highly unified project structure, lowering the cost of starting a new project.
Run the following command to generate a project that follows company conventions:
mvn archetype:generate -DarchetypeGroupId=com.geekhalo.lego -DarchetypeArtifactId=services-archetype -DarchetypeVersion=0.1.39-plugin_demo-SNAPSHOT -DgroupId=com.geekhalo -DartifactId=user -Dversion=0.1.39-plugin_demo-SNAPSHOTThe command creates a new project based on the services-archetype template with the specified groupId, artifactId, and version.
After execution, a user module appears with the following sub‑modules: user-domain: core domain models and logic (hexagonal core layer). user-infrastructure: technical implementations such as database access. user-app: application logic that depends on domain and infrastructure. user-api: external service contracts (Feign RPC and RocketMQ). user-feign-service and user-feign-client: SDK for other microservices. user-bootstrap: Spring Boot starter class.
The root contains pom.xml (Maven configuration) and README.md (project documentation).
3.2 Custom IDEA Plugin
After scaffolding, the IDEA plugin integrates the standards, dramatically reducing development cost.
3.2.1 Create Aggregate Root and View Model
Using the plugin, create an aggregate root “BasicUser” in the basic package of the domain module.
The plugin generates the necessary files across modules (domain, infrastructure, app, etc.).
3.2.2 Create Aggregate Root Method
Right‑click the aggregate root and select “Create Aggregate Root Method”. Define the method name as create. The plugin generates: CreateBasicUserCommand: command object with required parameters. CreateBasicUserContext: context object holding environment data. BasicUserCreatedEvent: event indicating successful creation.
It also adds static create and instance init methods to BasicUser, and a create method in BasicUserCommandApplication that coordinates the flow.
No manual service code is needed; the framework generates proxy classes to complete the process.
3.2.3 Create Query Method
In BasicUserQueryApplication, select “Create Query Method” and choose pagination. The plugin generates the following interface:
@QueryServiceDefinition(repositoryClass = BasicUserQueryRepository.class, domainClass = BasicUserView.class)
@Validated
public interface BasicUserQueryApplication {
// Pagination query method
Page<BasicUserView> pageOf(@Valid PageByStatus query);
}The PageByStatus query object is defined as:
@NoArgsConstructor
@Data
public class PageByStatus {
@FieldEqualTo("status")
private UserStatus status;
private Pageable pageable;
private Sort sort;
}This provides filtering by status, pagination, and sorting.
3.2.4 Additional Support
3.2.4.1 Common Enum
Creating an enum generates the enum class and a JPA converter. Example:
public enum UserStatus implements CommonEnum {
// code and description fields
private final int code;
private final String descr;
UserStatus(int code, String descr) { this.code = code; this.descr = descr; }
@Override public int getCode() { return this.code; }
@Override public String getDescription() { return this.descr; }
} @Converter(autoApply = true)
public class UserStatusConverter extends CommonEnumAttributeConverter<UserStatus> {
public UserStatusConverter() { super(UserStatus.values()); }
}3.2.4.2 Context Factory
@Component
@Slf4j
public class CreateBasicUserContextFactory extends AbstractSmartContextFactory<CreateBasicUserCommand, CreateBasicUserContext> {
public CreateBasicUserContextFactory() { super(CreateBasicUserCommand.class, CreateBasicUserContext.class); }
@Override
public CreateBasicUserContext create(CreateBasicUserCommand cmd) {
return CreateBasicUserContext.apply(cmd);
}
}3.2.4.3 Aggregate Root Factory
@Component
@Slf4j
public class BasicUserFactory extends AbstractSmartAggFactory<CreateBasicUserContext, BasicUser> {
public BasicUserFactory() { super(CreateBasicUserContext.class, BasicUser.class); }
@Override
public BasicUser create(CreateBasicUserContext context) {
return BasicUser.create(context);
}
}3.2.4.4 Business Validator
@Component
@Slf4j
public class CreateBasicUserPhoneValidator extends AbstractBusinessValidator<CreateBasicUserContext> {
public CreateBasicUserPhoneValidator() { super(CreateBasicUserContext.class); }
@Override
public void validate(CreateBasicUserContext context, ValidateErrorHandler validateErrorHandler) {
log.info("validate(context) {}", context);
}
}3.2.4.5 Result Converter
@Component
@Slf4j
public class BasicUserKeyConverter extends AbstractSmartResultConverter<BasicUser, CreateBasicUserContext, BasicUserKey> {
public BasicUserKeyConverter() { super(BasicUser.class, CreateBasicUserContext.class, BasicUserKey.class); }
@Override
public BasicUserKey convert(BasicUser agg, CreateBasicUserContext context) {
// conversion logic
return null;
}
}These generated components together provide a complete DDD‑oriented, CQRS‑compatible skeleton for the user service, allowing developers to focus on business logic while the framework handles boilerplate.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
