Skip to content

Maven plugin reference

The JoinedWorkz Maven plugin integrates CMN parsing, validation and generation into a Maven build. It is normally configured in the module that owns the CMN source models.

The plugin:

  • collects source models from the configured model source roots;
  • indexes CMN and Profile resources from the project's compile classpath so local models can reference them;
  • transforms and validates the local source models;
  • executes the cartridges selected by their platforms; and
  • writes generated artifacts through the active outlets.

Classpath models are library inputs. They participate in linking and indexing, but the plugin does not generate them as if they were local source models.

The plugin remains independent of individual facilities. Facilities contribute platforms, profiles, cartridges and their implementations as Maven dependencies. Outlet routes and generator properties belong in joinedworkz.properties, not in the plugin's Maven configuration.

For a shorter introduction, see:

1. Goals and build contract

The plugin coordinates are org.joinedworkz.cmn:cmn-maven-plugin. It provides generate for model generation and help for inspecting the packaged plugin contract. The following table describes the build-relevant generate goal:

generate goal factValue
Goalgenerate
Default phasegenerate-sources
Dependency resolutioncompile
Requires a Maven projectyes
Aggregator goalno
Inherited by defaultyes
Declared thread-safeyes
Maven version in the plugin descriptor3.8.6 or newer

The documentation examples use Maven 3.9 or newer.

When an execution declares <goal>generate</goal> without an explicit phase, Maven binds it to generate-sources. Commands such as mvn package and mvn verify therefore run generation before compilation.

The goal is not an aggregator. It runs in every reactor module in which the execution is effective. Prefer declaring it only in the model module. If it is declared in a parent under <build><plugins>, either ensure that inheritance is intentional or disable it for child modules:

xml
<plugin>
    <groupId>org.joinedworkz.cmn</groupId>
    <artifactId>cmn-maven-plugin</artifactId>
    <version>${joinedworkz.version}</version>
    <inherited>false</inherited>
    <!-- executions ... -->
</plugin>

1.1 Compile-classpath contract

Maven resolves the project's compile classpath before invoking the goal. Facility and profile artifacts must therefore be available through the model module's compile classpath. Normal compile dependencies and provided dependencies satisfy this requirement; test and runtime dependencies do not. Maven also includes system dependencies in this classpath, but system-scoped dependencies are not recommended for JoinedWorkz facilities.

The plugin receives Maven's compile-classpath elements, then removes:

  • the current project's main output directory;
  • the current project's test output directory;
  • blank entries; and
  • duplicate entries.

The resulting classpath is used to discover dependency models, facilities, profiles and cartridge implementations. Adding a facility only as a plugin dependency is not a substitute for adding it to the model project's dependencies.

1.2 Threading

The goal is declared threadSafe=true, so Maven may schedule it in a parallel reactor. JoinedWorkz nevertheless serializes complete, non-skipped generator executions with a static lock inside the loaded plugin runtime. Two JoinedWorkz generator executions in the same Maven process do not generate concurrently. Other thread-safe Maven work can still run in parallel.

Do not rely on mvn -T to make JoinedWorkz model generation itself parallel.

2. Minimal single-module configuration

This configuration uses a stable JoinedWorkz release, exposes model as a Maven resource and makes the Base facility available on the compile resolution path:

xml
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <joinedworkz.version>1.3.81</joinedworkz.version>
</properties>

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

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

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

The <?m2e ignore?> processing instruction prevents m2e from running this Maven execution during an Eclipse or JoinedWorkz Studio incremental build. Command-line Maven still executes it. Studio already provides its own interactive validation and generation.

Use the same JoinedWorkz version for the plugin and all facilities. Never mix facility versions within one build.

3. Parameter inventory

Most projects require no explicit plugin parameters beyond the execution. The following parameters are available for source discovery, validation and advanced Xtext integration.

To keep this reference readable on narrow screens, the overview tables only show names and types. Defaults, aliases and behavior follow directly below each group.

3.1 Model and language inputs

ParameterType
sourceRootsList<String>
javaSourceRootsList<String>
encodingString
languagesList<Language>

sourceRoots

  • Default: directories of all effective Maven <resources> in the current project.
  • Maven property alias: none.
  • Behavior: defines the local DSL source and generation set. An explicit list replaces the resource-derived default; it does not extend it.

The common setup is to declare the model directory as a Maven resource:

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

For a non-resource model directory, configure the parameter explicitly:

xml
<configuration>
    <sourceRoots>
        <sourceRoot>${project.basedir}/src/main/cmn</sourceRoot>
    </sourceRoots>
</configuration>

An explicit sourceRoots list controls model discovery only. It does not add those directories to the packaged Maven resources.

javaSourceRoots

  • Default: Maven's project.compileSourceRoots.
  • Maven property alias: none.
  • Behavior: supplies existing Java sources to the standalone builder's temporary stub-compilation step. It does not define where generated Java is written and does not add a compile source root to Maven.

An explicit list replaces the default:

xml
<configuration>
    <javaSourceRoots>
        <javaSourceRoot>${project.basedir}/src/main/java</javaSourceRoot>
        <javaSourceRoot>${project.basedir}/src/generated/java</javaSourceRoot>
    </javaSourceRoots>
</configuration>

Register generated Java separately as described in Generated Java sources.

encoding

  • Default: ${project.build.sourceEncoding}.
  • Maven property alias: xtext.encoding.
  • Behavior: configures DSL resource reading and generation through the standalone builder.

If the Maven expression resolves to no value, the plugin passes no explicit encoding and the language-specific encoding provider is used.

Prefer a project-wide setting:

xml
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Use -Dxtext.encoding=UTF-8 only when a command-line override is necessary. This parameter is not a replacement for the encoding configuration of the Maven Compiler Plugin.

languages

  • Default: no additional languages.
  • Maven property alias: none.
  • Behavior: appends additional Xtext language configurations after the built-in CMN and Profile registrations.

Each Language has:

  • setup: fully qualified Xtext setup class name;
  • javaSupport: whether the language links to or produces Java types, defaulting to true; and
  • optional Xtext outputConfigurations.

The setup class must be visible to the Maven plugin classloader. Additional languages are an advanced extension point and are not needed to add a normal JoinedWorkz facility. Do not redefine the .cmn or .profile extensions: later registrations for the same extension replace the earlier map entry.

3.2 Execution and validation

ParameterType
skipBoolean
failOnValidationErrorBoolean

skip

  • Default: false.
  • Maven property alias: xtext.generator.skip.
  • Behavior: when true, exits before source discovery, validation, platform mapping and generation.

Examples:

bash
mvn generate-sources -Dxtext.generator.skip=true
xml
<configuration>
    <skip>true</skip>
</configuration>

A successful Maven build with this flag proves only that generation was skipped. It does not prove that existing generated files are current.

failOnValidationError

  • Default: true.
  • Maven property alias: none.
  • Behavior with true: an unsuccessful validation result fails the Maven goal. With the default non-clustered processing, the source models are validated before generation.
  • Behavior with false: validation still runs, but the standalone builder attempts generation despite validation errors and the Mojo does not fail merely because the builder returned an unsuccessful validation result.

Keep the default in normal builds and CI:

xml
<configuration>
    <failOnValidationError>true</failOnValidationError>
</configuration>

false does not suppress fatal configuration, loading, I/O or generator exceptions. A duplicate CMN package is also always fatal. In addition, JoinedWorkz reports the final unknown/unused-property summary only after a successful builder run; a failed validation result with failOnValidationError=false therefore does not produce that final summary.

When resource clustering is enabled, an earlier successful cluster may already have produced output before validation fails in a later cluster. Treat output from every failed build as incomplete.

3.3 Internal Java stub compiler

These parameters configure the Java compiler used internally by Xtext while it builds temporary stubs. They do not configure the final Maven compilation of your generated application sources.

ParameterType
compilerSourceLevelString
compilerTargetLevelString
compilerSkipAnnotationProcessingBoolean
compilerPreserveInformationAboutFormalParametersBoolean

Source and target levels

  • compilerSourceLevel defaults to 1.6 and has the Maven property alias maven.compiler.source.
  • compilerTargetLevel defaults to 1.6 and has the Maven property alias maven.compiler.target.

The 1.6 values are implementation defaults, not a current recommendation. Set both properties explicitly to the Java level used by the project:

xml
<properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
</properties>

maven.compiler.release is not connected to these plugin parameters. A project that configures only:

xml
<maven.compiler.release>21</maven.compiler.release>

still leaves the JoinedWorkz internal compiler at its 1.6 source and target defaults. If the project uses release, also set maven.compiler.source and maven.compiler.target, or configure compilerSourceLevel and compilerTargetLevel directly:

xml
<configuration>
    <compilerSourceLevel>21</compilerSourceLevel>
    <compilerTargetLevel>21</compilerTargetLevel>
</configuration>

Annotation processing

compilerSkipAnnotationProcessing defaults to false. When true, the internal compiler uses the equivalent of -proc:none:

xml
<configuration>
    <compilerSkipAnnotationProcessing>true</compilerSkipAnnotationProcessing>
</configuration>

This setting does not disable annotation processing in the Maven Compiler Plugin.

Formal parameter metadata

compilerPreserveInformationAboutFormalParameters defaults to false. When true, the internal compiler preserves formal parameter names with the equivalent of -parameters:

xml
<configuration>
    <compilerPreserveInformationAboutFormalParameters>true</compilerPreserveInformationAboutFormalParameters>
</configuration>

The Maven property maven.compiler.parameters is not an alias for this parameter. Configure final application compilation separately.

3.4 Dependency-model lookup and memory

ParameterType
classPathLookupFilterString
clusteringConfigClusteringConfig

classPathLookupFilter

  • Default: no filter.
  • Maven property alias: none.
  • Behavior: a Java regular expression is matched against the complete path of every compile-classpath entry. Only matching entries are scanned for dependency DSL resources.

Java regular-expression matches() semantics apply, so use .* when the relevant text may occur in the middle of the path:

xml
<configuration>
    <classPathLookupFilter>.*joinedworkz.*\.jar</classPathLookupFilter>
</configuration>

Use this parameter only when classpath model discovery is demonstrably too broad or expensive. It does not remove entries from:

  • Java type lookup;
  • temporary stub compilation;
  • cartridge or strategy loading; or
  • the model module's Maven dependency graph.

An overly narrow expression can hide required profiles or imported library models and cause linking errors.

clusteringConfig

  • Default: clustering disabled when the entire block is absent.
  • Maven property alias: none.
  • Behavior: enables Xtext's memory-sensitive resource clustering. It does not enable parallel generation.

The nested Xtext values and their defaults are:

Nested valueDefault
minimumFreeMemory10 MB
minimumClusterSize20 resources
minimumPercentFreeMemory15 percent

Example:

xml
<configuration>
    <clusteringConfig>
        <minimumFreeMemory>256</minimumFreeMemory>
        <minimumClusterSize>20</minimumClusterSize>
        <minimumPercentFreeMemory>15</minimumPercentFreeMemory>
    </clusteringConfig>
</configuration>

Enable clustering only for builds whose model volume or memory pressure requires it, then verify generation of the complete model set.

3.5 Temporary builder directory

ParameterType
tmpClassDirectoryString

tmpClassDirectory

  • Default: ${project.build.directory}/xtext-temp.
  • Maven property alias: none.
  • Behavior: root directory for temporary generated stubs and compiled stub classes.

This directory is not a JoinedWorkz outlet and is not the destination of application source generation. Keep custom values below Maven's build directory unless there is a specific reason not to:

xml
<configuration>
    <tmpClassDirectory>${project.build.directory}/joinedworkz-xtext</tmpClassDirectory>
</configuration>

The plugin creates the directory but does not clean it itself. The normal default is removed by mvn clean because it is below target.

4. Platform resource mappings

Platform resource mappings resolve EMF URIs such as:

text
platform:/resource/project-name/path/to/resource

They do not:

  • control Maven reactor order;
  • put an artifact on the compile classpath;
  • route JoinedWorkz outlets; or
  • replace Maven dependencies.

4.1 Manual projectMappings

ParameterType
projectMappingsList<ProjectMapping>

Each mapping contains:

  • projectName: the first path segment after platform:/resource/; and
  • path: the corresponding project directory.

Example:

xml
<configuration>
    <projectMappings>
        <projectMapping>
            <projectName>shared-model</projectName>
            <path>${project.parent.basedir}/shared-model</path>
        </projectMapping>
        <projectMapping>
            <projectName>service-model</projectName>
            <path>${project.basedir}</path>
        </projectMapping>
    </projectMappings>
</configuration>

Entries missing either value are ignored.

4.2 Automatic autoFillPlatformResourceMap

ParameterType
autoFillPlatformResourceMapBoolean
  • Default: false.
  • Maven property alias: none.
  • Behavior: when enabled, registers the current project directory, its declared child modules and recursively each Maven parent plus that parent's declared modules.
xml
<configuration>
    <autoFillPlatformResourceMap>true</autoFillPlatformResourceMap>
</configuration>

The map key is the directory name. This is not a general filesystem scan. Sibling mappings arise only when a parent declares those sibling modules.

Automatic mappings are added first. Explicit projectMappings are applied afterwards and therefore replace an automatic entry with the same key. If different relevant directories share the same directory name, use explicit, unambiguous project names instead of relying on automatic mapping.

5. Multi-module projects

A common reactor separates model ownership from generated and handwritten application code:

text
project/
├── pom.xml
├── model/
│   ├── pom.xml
│   ├── joinedworkz.properties
│   └── src/main/cmn/
├── backend-generated/
│   └── pom.xml
└── backend-app/
    └── pom.xml

For a sequential reactor build, list the model module before modules that compile or package its generated output:

xml
<modules>
    <module>model</module>
    <module>backend-generated</module>
    <module>backend-app</module>
</modules>

Configure cmn-maven-plugin in model, not in every consumer module. Route outputs from model/joinedworkz.properties, for example:

properties
outlet.generatedJavaSource.directory=../backend-generated/src/generated/java
outlet.generatedConfiguration.directory=../backend-app/src/generated/resources

Do not rely on this <modules> order as synchronization in a parallel mvn -T build. Maven may build otherwise independent consumer modules while the model module is still generating files. Use a sequential reactor build for filesystem-based cross-module output, or establish a real Maven dependency that orders every consumer after the model module. The generator's internal lock serializes generator executions only; it does not delay compilation in other modules.

Then register those exact directories in the consuming modules. Platform resource mappings are only necessary when models actually use platform:/resource/... URIs; ordinary sibling outlet routing does not require autoFillPlatformResourceMap.

For the complete layout and outlet rules, see Multi-module setup with outlet overrides.

6. Registering generated output

Writing a file and making Maven consume it are separate responsibilities. Outlet configuration chooses the destination. The target module's POM must register that destination when it should be compiled or packaged.

Generated resources

For output routed to src/generated/resources:

xml
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
        <resource>
            <directory>src/generated/resources</directory>
        </resource>
    </resources>
</build>

Configure this in the module that receives the files. OpenAPI documents, diagrams and generated configuration may be routed to different modules and directories.

Generated Java sources

Generated Java must be registered as a compile source root. One option is the Build Helper Maven Plugin:

xml
<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>${project.basedir}/src/generated/java</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

The registered directory must match the effective outlet route. Registration does not clean generated files and does not determine whether they are replaceable. See Generated output, ownership and regeneration.

7. joinedworkz.properties

The plugin reads joinedworkz.properties from the base directory of the module in which it runs. In a multi-module build, that is normally the model module, not the reactor root.

Use the file for:

  • global and layer-specific outlet directories;
  • package overrides;
  • cartridge activation; and
  • facility-defined generator properties.

Example:

properties
outlet.generatedJavaSource.directory=../backend-generated/src/generated/java
outlet.generatedJavaSource.commons.directory=../commons/src/generated/java

Maven plugin parameters and JoinedWorkz properties are different configuration layers. For example:

  • sourceRoots tells the Maven/Xtext builder where local model files are;
  • outlet.<outlet>.directory tells cartridges where generated files go.

The complete key inventory, parsing rules, precedence and diagnostics are in the joinedworkz.properties reference.

8. Diagnostics and troubleshooting

This section covers Maven-specific symptoms. For a phase-oriented path across Maven, Studio, configuration, outlets, Flyway and consumer builds, start with the central Troubleshooting reference.

No source models are collected

Check that the model directory is either:

  • an effective Maven <resource>; or
  • present in an explicit sourceRoots list.

An explicit list replaces all resource-derived source roots. Run Maven with debug output and inspect the Source dirs: line:

bash
mvn -X generate-sources

A platform, profile, cartridge or imported model is unavailable

Check the model module's dependency tree:

bash
mvn dependency:tree

The required facility or profile must be on the compile resolution path. provided is valid; test and runtime are not. Also check whether classPathLookupFilter hides the required dependency model.

Internal Java stub compilation uses the wrong language level

The generator log reports:

text
Compiler source level: ...
Compiler target level: ...

Set maven.compiler.source and maven.compiler.target explicitly. maven.compiler.release alone does not configure the JoinedWorkz internal compiler.

Maven succeeds but expected output is missing

Check:

  • whether xtext.generator.skip or <skip> is enabled;
  • whether failOnValidationError=false allowed Maven to continue after model errors;
  • whether the expected platform and cartridge are active;
  • the effective outlet route in joinedworkz.properties; and
  • the module in which the plugin actually executed.

Do not use committed or stale generated files as proof of a successful current generation. Clean only directories that are explicitly owned as replaceable output.

A validation error does not stop the build

Remove <failOnValidationError>false</failOnValidationError> and use the default true. Fatal configuration and generator errors remain fatal in both modes, and duplicate CMN package names always stop the build.

Platform-resource URIs do not resolve

Use projectMappings when the URI's project-name segment differs from the directory name or when the project is not reachable through the current Maven parent/module structure. Do not use platform mappings to solve an absent Maven dependency or an outlet-routing problem.

The temporary directory cannot be created

Keep tmpClassDirectory writable and preferably below ${project.build.directory}. It is temporary compiler state, not a generated source outlet.

Inspect the effective plugin contract

Run the packaged help goal in the model module that declares the JoinedWorkz Maven plugin:

bash
mvn cmn:help -Ddetail=true -Dgoal=generate

Compare the resolved plugin version in the output with the facility versions in the model module. Omit -Dgoal=generate to include every packaged goal, or omit -Ddetail=true as well for the compact goal overview.

9. Maven-injected values

The plugin descriptor also contains two required, read-only values. Users cannot configure them as normal plugin options:

Injected valueType and source
projectMavenProject, from ${project}
classpathElementsList<String>, from ${project.compileClasspathElements}

They explain why plugin behavior is module-specific and why facilities must be on the model module's compile resolution path.

10. Checklist

For a normal JoinedWorkz Maven integration:

  1. Use the same stable JoinedWorkz version for the plugin and facilities.
  2. Put facilities and profiles on the model module's compile or provided classpath.
  3. Configure the generate goal in the model module.
  4. Declare model directories as Maven resources or explicit sourceRoots.
  5. Set UTF-8 plus explicit maven.compiler.source and maven.compiler.target.
  6. Route outputs in joinedworkz.properties.
  7. Register generated source and resource directories in their consuming modules.
  8. Keep failOnValidationError=true in normal builds.
  9. Define generated-output ownership and cleanup explicitly.