Skip to content

Generates a full backend application using the provided ‘layout’ property

Sample configuration:

config {
    basePackage "com.example"
    persistence jpa
    databaseType postgresql
    layout CleanHexagonalProjectLayout

    // The IDE will automatically use the active .zdl file
    // Alternatively, specify the path here to maintain separation between models and plugins
    zdlFile "models/example.zdl"

    plugins {
        BackendApplicationDefaultPlugin {
            useLombok true
            --force // overwrite all files
        }
    }
}

Visit https://www.zenwave360.io/docs/zenwave-sdk/backend-application for complete documentation.

OptionDescriptionTypeDefaultValues
layoutProject organization and package structure (documentation)ProjectLayoutDefaultProjectLayoutDefaultProjectLayout, CleanHexagonalProjectLayout, LayeredProjectLayout, SimpleDomainProjectLayout, HexagonalProjectLayout, CleanArchitectureProjectLayout
zdlFileZDL file to parseString
zdlFilesZDL files to parse (comma separated)List
basePackageJava Models package nameStringio.example.domain.model
persistencePersistencePersistenceTypemongodbmongodb, jpa
databaseTypeSQL database flavorDatabaseTypepostgresqlgeneric, postgresql, mysql, mariadb, oracle
styleProgramming StyleProgrammingStyleimperativeimperative, reactive
useLombokUse @Getter and @Setter annotations from Lombokbooleanfalse
useSpringModulithWhether to use Spring Modulith annotations and featuresbooleanfalse
useJSpecifyWhether to use JSpecify for nullability annotationsbooleanfalse
useJMoleculesWhether to add jMolecules DDD and architecture annotations to generated codebooleanfalse
addRelationshipsByIdControls whether to add a read/write relationship by id when mapping relationships between aggregate (not recommended) keeping the relationship by object readonly.booleanfalse
idJavaTypeSpecifies the Java data type for the ID fields of entities. Defaults to Long for JPA and String for MongoDB if not explicitly set.String
includeEmitEventsImplementationWhether to add AsyncAPI/ApplicationEventPublisher as service dependencies. Depends on the naming convention of zenwave-asyncapi plugin to work.booleantrue
targetFolderTarget folder to generate code to. If left empty, it will print to stdout.File
continueOnZdlErrorContinue even when ZDL contains fatal errorsbooleantrue
formatterCode formatter implementationFormatterspalantirpalantir, spring, google
skipFormattingSkip java sources output formattingbooleanfalse
haltOnFailFormattingHalt on formatting errorsbooleantrue

Set useJMolecules true to annotate generated code with jMolecules DDD and architecture stereotypes. Annotations are emitted as fully qualified names, so the SDK itself needs no jMolecules dependency — only the generated project does:

<dependency>
    <groupId>org.jmolecules</groupId>
    <artifactId>jmolecules-ddd</artifactId>
</dependency>
<dependency>
    <groupId>org.jmolecules</groupId>
    <artifactId>jmolecules-events</artifactId>
</dependency>
<!-- plus jmolecules-hexagonal-architecture or jmolecules-layered-architecture, matching your layout -->
<dependency>
    <groupId>org.jmolecules.integrations</groupId>
    <artifactId>jmolecules-archunit</artifactId>
    <scope>test</scope>
</dependency>

The architecture vocabulary follows from layout, with no separate option to set:

layoutarchitecture
DefaultProjectLayout, CleanHexagonalProjectLayout, HexagonalProjectLayoutHEXAGONAL
LayeredProjectLayoutLAYERED
SimpleDomainProjectLayout, CleanArchitectureProjectLayoutNONE, DDD annotations only

What each generated artifact receives:

artifactDDDHEXAGONALLAYERED
entity@AggregateRoot or @Entity, @Identity on the id@DomainLayer
repository@Repository@SecondaryPort@InfrastructureLayer
domain event (not @asyncapi)@DomainEvent@DomainLayer
service interface@PrimaryPort@ApplicationLayer
service implementation@Application@ApplicationLayer
input / output DTO, @vo / @embedded entity@ValueObject
controller, event listener, asyncapi consumer@PrimaryAdapter@InterfaceLayer
event publisher port@SecondaryPort
event publisher implementation@SecondaryAdapter@InfrastructureLayer
Spring Modulith package-info@Module

@vo and @embedded entities are annotated @ValueObject, like inbound DTOs. @asyncapi events are payload DTOs generated from the contract, so they are never @DomainEvent.

A JMoleculesArchitectureTest is generated alongside, verifying the stereotypes with ArchUnit. Unlike ArchitectureTest, which matches package names, these rules read the annotations, so they hold for any layout. It is written once and never overwritten, so edits you make to it are permanent.

Two things worth knowing:

  • aggregateReferencesShouldBeViaIdOrAssociation rejects any direct reference to an @AggregateRoot. A bidirectional relationship such as Customer{addresses} to Address{customer} generates exactly that, so the rule reports it. Comment out its @ArchTest to opt out.
  • No ensureLayering() rule is generated for LAYERED. That rule encodes Evans’ layering, where infrastructure sits below the domain and may not reference it, while LayeredProjectLayout is the three tier web -> service -> repository. A Spring Data repository names its aggregate in its own type signature, so the rule could never pass. The layer annotations still document the tiers.
jbang zw -p io.zenwave360.sdk.plugins.BackendApplicationDefaultPlugin --help