Backend Development 16 min read

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.

macrozheng
macrozheng
macrozheng
Boost Java Backend Development with DDD, CQRS, and Automated Maven Archetype Generation

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:

<code>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-SNAPSHOT</code>

The 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:

<code>@QueryServiceDefinition(repositoryClass = BasicUserQueryRepository.class, domainClass = BasicUserView.class)
@Validated
public interface BasicUserQueryApplication {
    // Pagination query method
    Page<BasicUserView> pageOf(@Valid PageByStatus query);
}</code>

The

PageByStatus

query object is defined as:

<code>@NoArgsConstructor
@Data
public class PageByStatus {
    @FieldEqualTo("status")
    private UserStatus status;
    private Pageable pageable;
    private Sort sort;
}</code>

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:

<code>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; }
}</code>
<code>@Converter(autoApply = true)
public class UserStatusConverter extends CommonEnumAttributeConverter<UserStatus> {
    public UserStatusConverter() { super(UserStatus.values()); }
}</code>

3.2.4.2 Context Factory

<code>@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);
    }
}</code>

3.2.4.3 Aggregate Root Factory

<code>@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);
    }
}</code>

3.2.4.4 Business Validator

<code>@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);
    }
}</code>

3.2.4.5 Result Converter

<code>@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;
    }
}</code>

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.

Javacode generationbackend developmentmavenDDDSpringBootCQRS
macrozheng
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.