Skip to content

Integrate into an existing Java project

This guide shows how to add JoinedWorkz step by step to an existing Java project, without rewriting everything from scratch.

Typical goals are:

  • generate OpenAPI for existing or planned REST APIs
  • generate DTOs / API interfaces and use them from hand-written code
  • gradually move parts of the API and domain model into CMN models

We’ll focus on Maven-based projects. The examples assume you use Java 21 and, for REST, a Spring Boot stack – but the patterns apply to other Java technologies as well.

For background reading see:

Release and evidence boundary

This guide targets JoinedWorkz 1.3.80, Java 21 and Maven 3.9+. Its model snippets and release behavior were source- and syntax-checked by 2026-07-26. It is an adoption pattern, not a separately built canonical project. Use the linked Quickstart, Spring Boot release example and multi-module guide for their exact build and output evidence.


1. Integration strategies

There is no single “right” way to introduce JoinedWorkz into an existing project. In practice, three patterns work well:

  1. Model inside an existing module
    Put CMN models directly into an existing Maven module (for example the REST API module) and generate OpenAPI and DTOs alongside your current code.

  2. Dedicated model module (recommended for larger systems)
    Create a new Maven module that only contains CMN models and the JoinedWorkz plugin, and route generated artefacts into existing modules via joinedworkz.properties.

  3. Hybrid approach
    Start with (1) inside an existing module, and later extract the models into a dedicated module when the model grows.

This guide will show the first two approaches, so you can choose what fits your project best.


2. Prerequisites

Your existing project should:

  • be built with Maven
  • use Java 21 (aligned with JoinedWorkz 1.3.80 examples)
  • use Maven 3.9 or newer
  • have a module where it makes sense to introduce API/domain modelling (e.g. a “web”, “api”, “service” or “backend” module)

You also need:

  • JoinedWorkz Studio installed (optional but highly recommended)
  • access to Maven Central (for the JoinedWorkz facilities and plugin)

The basic dependencies are:

xml
<properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <joinedworkz.version>1.3.80</joinedworkz.version>
</properties>

<dependencies>
    <!-- Spring Boot platform (includes Java and Base via transitive dependencies) -->
    <dependency>
        <groupId>org.joinedworkz.facilities</groupId>
        <artifactId>spring-boot</artifactId>
        <version>${joinedworkz.version}</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

You can also depend only on common-base or common-java if you do not use Spring Boot, see Facilities & platforms.


3. Option A – Integrate into an existing module

This is the simplest way to start. You:

  • add the JoinedWorkz plugin to an existing Maven module
  • add a model/ folder with CMN models
  • register generated resources/sources if needed

3.1 Add the plugin and facilities

In the existing module where you want to introduce modelling (for example your REST API module), update the POM:

xml
<build>
    <resources>
        <!-- existing resources -->
        <resource>
            <directory>src/main/resources</directory>
        </resource>

        <!-- CMN models -->
        <resource>
            <directory>model</directory>
        </resource>

        <!-- generated resources (e.g. OpenAPI) -->
        <resource>
            <directory>src/generated/resources</directory>
        </resource>
    </resources>

    <plugins>
        <!-- JoinedWorkz generator -->
        <plugin>
            <groupId>org.joinedworkz.cmn</groupId>
            <artifactId>cmn-maven-plugin</artifactId>
            <version>${joinedworkz.version}</version>
            <executions>
                <execution>
                    <?m2e ignore?><!-- ignore this execution in Eclipse -->
                    <goals>
                        <goal>generate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

        <!-- register generated Java sources (optional, if you generate Java) -->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
            <version>3.6.0</version>
            <executions>
                <execution>
                    <id>add-generated-source</id>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>add-source</goal>
                    </goals>
                    <configuration>
                        <sources>
                            <source>${basedir}/src/generated/java</source>
                        </sources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Add the Spring Boot facility (or the facility you need) as a dependency:

xml
<dependencies>
    <!-- JoinedWorkz facilities (SpringBoot, brings in Java + Base) -->
    <dependency>
        <groupId>org.joinedworkz.facilities</groupId>
        <artifactId>spring-boot</artifactId>
        <version>${joinedworkz.version}</version>
        <scope>provided</scope>
    </dependency>

    <!-- your existing dependencies -->
    ...
</dependencies>

3.2 Add a first CMN model

Create a model/ directory next to src/main/java and src/main/resources and add a CMN file, for example:

  • model/customer-api.cmn
cmn
api package com.example.existing.api

import org.joinedworkz.facilities.common.base
import org.joinedworkz.facilities.common.base.api
import org.joinedworkz.facilities.profiles.springboot
import org.joinedworkz.facilities.springboot.api

platform SpringBoot

type<entity> Customer {
    id**:       Id
    firstName*: Name
    lastName*:  Name
    email:      String(255)
}

resource /customers as Customer[] by id {

    queryEntities()
    createEntity()
    readEntity()
    updateEntity()
    deleteEntity()
}

You can now:

  • run mvn clean package
  • or open the project in JoinedWorkz Studio and generate from there

With the default outlets from Base and SpringBoot, inspect these configured output directories:

  • src/generated/resources/openapi for model-scoped OpenAPI;
  • diagram/api for matching OpenAPI viewers;
  • src/generated/java for Java output selected by the platform.

The exact file names derive from the effective model and component namespaces. This illustrative integration fragment is not assigned invented expected file names. See the Spring Boot example for release-built, exact paths.

The resource-only model above produces the model-scoped OpenAPI document. In SpringBoot 1.3.80, add a component with provide /customers before expecting a generated API interface or controller. That component also produces the additional component-scoped OpenAPI aggregate.

3.3 Use generated artefacts from existing code

How you integrate the generated artefacts depends on what you generate:

  • OpenAPI
    Use the generated YAML/HTML as the source of truth for your API docs, or feed the OpenAPI into your existing tooling (e.g. client generation).

  • DTOs Let JoinedWorkz generate DTOs and reference them from your hand-written controllers or services instead of writing DTOs by hand.

  • API interfaces and controllers Define a component that provides the resource. SpringBoot generates the API interface and controller from that provide boundary, not from a resource model alone. Treat the generated files as replaceable output. Keep business logic in project-owned services outside src/generated/**; do not adopt generated controller files as manually maintained sources. The canonical release example calls its generated CustomerDataAccessService directly and does not demonstrate a manual handler layer.

    See also Spring Boot facility

A common pattern is:

  1. generate DTOs from CMN,
  2. add a component provide boundary when you want a generated API interface/controller and component OpenAPI aggregate,
  3. keep manual business logic behind the generated boundary,
  4. let the CMN model and facilities handle OpenAPI and documentation.

4. Option B – Add a dedicated model module

For larger projects or when you want to keep modelling concerns separate, create a dedicated model module and route outputs into existing modules.

4.1 Create a model module

Add a new Maven module (for example model) to your multi-module project:

xml
<modules>
    <module>model</module>
    <module>backend</module>
    <module>webapp</module>
    ...
</modules>

In model/pom.xml:

xml
<project>
    ...
    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <joinedworkz.version>1.3.80</joinedworkz.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.joinedworkz.facilities</groupId>
            <artifactId>spring-boot</artifactId>
            <version>${joinedworkz.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>model</directory>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.joinedworkz.cmn</groupId>
                <artifactId>cmn-maven-plugin</artifactId>
                <version>${joinedworkz.version}</version>
                <executions>
                    <execution>
                        <?m2e ignore?><!-- ignore this execution in Eclipse -->
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

In this module you only keep:

  • CMN models (e.g. domain, API, backend components)
  • no hand-written Java code

4.2 Route outputs with layers and facility-specific outlets

Use joinedworkz.properties in the root of the model module (or project) to route generated outputs into existing modules. A layer such as core can select a source-tag-specific directory when the responsible generator passes that layer. Other outputs must use their actual facility outlet.

Example for a project with:

  • backend module (services, domain, persistence)
  • webapp module (Spring Boot application, controllers, HTTP boundary)

model/joinedworkz.properties:

properties
# default for generated Java sources
outlet.generatedJavaSource.directory=src/generated/java

# domain-related Java code (core layer) to backend module
outlet.generatedJavaSource.core.directory=../backend/src/generated/java

# SpringBoot controller/API output to web module
outlet.generatedApiSource.directory=../webapp/src/generated/java

# OpenAPI and HTML viewers globally to the web module
outlet.generatedOpenApi.directory=../webapp/src/generated/resources/openapi
outlet.generatedOpenApiHtml.directory=../webapp/diagram/api

The exact outlet names depend on the platform (see the Base and SpringBoot profiles):

  • outlet.<outletName>.directory – default directory
  • outlet.<outletName>.<sourceTag>.directory – source-tag mapping, but only when the generator passes that tag

In release 1.3.80, Java generators writing to generatedJavaSource can use the CMN layer as their source tag. SpringBoot controller/API output uses the distinct generatedApiSource outlet; the global override above also catches output derived from an untagged component model. The Base OpenAPI and OpenAPI HTML generators do not pass a source tag, so their mappings above are also deliberately global. Make sure the target modules (backend, webapp, …) register these directories as resources or sources as described in the Maven plugin reference.

4.3 Build order in the parent POM

In a multi-module setup, ensure that the model module is built first so that generated artefacts are available when compiling dependent modules.

In the parent pom.xml:

xml
<modules>
    <module>model</module>
    <module>backend</module>
    <module>webapp</module>
</modules>

Maven respects the module order (as long as there are no conflicting dependency cycles), so the generators in model run before backend and webapp are compiled.


5. Gradual adoption patterns

You do not need to model the whole existing system at once. Common gradual steps are:

  1. OpenAPI only
    Start by modelling just the REST resources in CMN and generate OpenAPI and diagrams. Keep all implementation code unchanged.

  2. Introduce DTOs
    Add CMN types (entities, projections) and let JoinedWorkz generate DTOs. Use the generated DTOs in your existing controllers/services instead of hand-written ones.

  3. Introduce component / application models
    Use a component to combine all endpoints in its provide declarations into an additional component-scoped OpenAPI document, even when the resources come from several imported CMN models. Applications add the higher-level diagrams; release 1.3.80 does not create another OpenAPI aggregate per application.

  4. Optional: Generated API interface and controller

    When you are comfortable with the model, let the SpringBoot platform generate an API interface and controller from the component's provide boundary. Keep additional manual business services outside the replaceable generated tree.

Throughout this process, your existing Java code remains in control of the runtime behaviour. JoinedWorkz augments the project with generated artefacts that you can adopt step by step.


6. Summary

To integrate JoinedWorkz into an existing Java project:

  1. Decide on a strategy

    • integrate into an existing module, or
    • create a dedicated model module and route outputs via outlets.
  2. Add the facilities and Maven plugin
    Include the appropriate facility (Base, Java, SpringBoot, …) and configure the cmn-maven-plugin as described above.

  3. Create CMN models
    Start small – for example with one API and its key types – and grow the model over time.

  4. Configure resources and generated sources
    Register generated resource/source directories in the modules that use them.

  5. Use the generated artefacts
    Wire OpenAPI, DTOs and (optionally) generated API/controller boundaries into your existing project, gradually replacing hand-written boilerplate where it makes sense.

For concrete CMN examples, see: