Imported model processing and diagnostics
Advanced modeling
Most projects only import model elements so they can reference them. This page describes when an importing model's Platform adds Cartridge processing to an imported model, and which validation and ownership boundaries still apply. The executable example is in example-custom-facility.
1. An import does not merge models
A CMN import makes another package visible. The imported model remains a separate model with its own:
- package namespace;
- Platform selection, if it declares one;
- source file;
- validation unit and, where source-mapped, diagnostic location; and
- declared layer.
The importing model does not replace the imported model's namespace or existing Platform selection. Duplicate package namespaces are therefore still invalid, and an import is not a way to distribute one package across several source files.
Additional files for an imported model are produced as part of the importing generator run. They use that run's effective properties and configured Outlets; the imported model does not acquire an independent Outlet configuration.
2. Base-to-TextReport example
The public Custom Facility example provides a focused composition case. TextReport specializes the stable Base Platform and contributes one TextReportCartridge.
The imported model has its own namespace and selects Base:
package org.joinedworkz.examples.textreport.imported
import org.joinedworkz.facilities.common.profiles.base
platform Base
type ImportedExample {
}The separate wrapper imports that model and selects TextReport:
package org.joinedworkz.examples.textreport.wrapper
import org.joinedworkz.examples.textreport.imported
import org.joinedworkz.examples.textreport.profile
platform TextReportThe imported model's Platform already supplies the Base Cartridges. JoinedWorkz therefore adds only the missing TextReportCartridge while processing it for the wrapper. The wrapper does not replace the imported model's Base Platform or namespace.
The example's Maven test checks all three reports, including the direct consumer as a control case:
target/generated-text-report/
└── org/joinedworkz/examples/textreport/
├── consumer/model-summary.txt
├── imported/model-summary.txt
└── wrapper/model-summary.txtRemoving the wrapper and running clean generation removes the wrapper report and, critically, the imported model's TextReport. The imported model continues to be a valid Base model; it receives the custom report only through the additional Platform processing.
This is an advanced composition mechanism. The exact generated files still depend on the imported model, the selected Platforms, active Cartridges, Outlet routing and Facility configuration. The complete Facility and direct consumer setup is in Build a custom Facility.
3. Which Cartridges are added
JoinedWorkz first determines the active Cartridge instances of the importing model. CMN exclusions, cartridge.<cartridgeName>.enabled and the Profile application setting apply before imported models are processed. A Cartridge that is excluded or disabled for the importer is therefore not added to an import.
For each eligible import, JoinedWorkz compares those active Cartridges with the Cartridge applications supplied by the imported model's own Platform:
- an application already supplied by that Platform is not added again;
- a missing active application is applied to the imported model; and
- a model without its own Platform can receive the active applications of the importer.
See Cartridge enablement for the general exclusion and configuration precedence.
Finalizing additional import processing
Set finalized=true on an imported root model when no importer should add further Cartridge processing to it:
package com.example.shared finalized=trueSet the same property on one import declaration to finalize only that import edge:
import com.example.shared finalized=trueIf either value is true, JoinedWorkz skips the additional processing through that import. The import still makes the package visible for references, and the imported model can still be generated normally with its own Platform. finalized=false on one side does not override true on the other.
Use finalized only when this broad boundary is intended. It suppresses all additional Cartridges for that import, not one selected Cartridge.
4. Processing and failure order
JoinedWorkz treats every model as its own processing unit. For an importing model, the relevant order is:
- transform, prepare and validate the importing model;
- for each eligible import:
- transform, prepare and validate that imported model with the additional active Cartridges;
- process its nested imports recursively; and
- generate that imported model's additional output;
- after all imports succeed, generate output for the importing model.
An imported model is validated before its additional output is written. If that validation fails, JoinedWorkz does not generate the output of the dependent importing model.
This ordering is not a transaction across the complete Maven build. Output from an unrelated model or an earlier successfully processed import is not rolled back if a later import fails. Use a clean consumer build when you need an authoritative generated-output result.
JoinedWorkz also guards one generator invocation against processing the same model repeatedly. Cyclic imports therefore do not cause endless recursive generation.
5. Output routing and ownership
Additional output is part of the importing generator run. It uses that run's effective joinedworkz.properties and configured Outlets. The imported model does not acquire a second independent Outlet configuration.
The Cartridge still receives the imported model as its current model. It can therefore derive file names from that model's namespace, and the model's layer becomes the default source tag where the Outlet uses source-tag routing. In the TextReport example, both reports use the wrapper's configured generatedTextReport Outlet, while the imported report remains under org/joinedworkz/examples/textreport/imported.
Authoritative ownership also remains separate:
- edit the imported CMN source to change the imported model;
- edit the wrapper to change the additional Platform relationship; and
- treat replaceable output from both models according to the Outlet's cleanup contract.
6. Validation belongs to the imported model
A Cartridge validates exactly the model that JoinedWorkz passes to it. It must not recursively validate imported models or follow cross-resource references in search of additional validation targets. The generic generation pipeline invokes the appropriate validation separately for every processed model.
This separation is important for both correctness and Studio performance:
- a problem is attached to the model element that violates the rule;
- a Cartridge does not redundantly traverse models that the pipeline processes as separate units; and
- generation does not repeat checks that already belong to the validation phase.
Facility developers should follow the dedicated Cartridge validation and diagnostics contract.
7. Diagnostics in JoinedWorkz Studio
When a Cartridge reports a Core issue target with an available source mapping, and both models are editable resources in the same Studio project, the problem is shown at the original element in the imported model. Imported widgets are one supported example. Correcting and saving that imported resource reruns the affected importing models and removes their obsolete markers. Markers from independent importing models are owned and replaced independently.
For sources that are not editable in the same Studio project, use the Maven build as the authoritative diagnostic path. An exact Studio editor marker is not guaranteed for such a source.
Unexpected failures during transformation, preparation or generation are still generator failures. They are reported separately from normal Cartridge-validation diagnostics.
8. Related but different mechanisms
Imported-model processing is not:
- a Maven multi-module dependency by itself;
- a Package Override or Java import rewrite;
- a way to merge duplicate CMN namespaces; or
- required for the normal Quickstart.
For the three separate steps—Facility dependency, CMN import and Platform selection—see Profiles and platforms. For basic import syntax, see File header and packages.
