The Tentackle Wizard Maven Plugin¶
The tentackle-wizard-maven-plugin is a developer productivity tool. While the
tentackle-maven-plugin
and the wurbelizer take care of generating the persistence layer from an existing
model, the wizard plugin helps you
author the source files that carry that model in the first place.
It scaffolds the Java source files for new
PDOs and
operations, filling in the boilerplate
(interfaces, implementations, the remote layer, the model comment block, class IDs, package
declarations, wurblet anchors) so that all you have to do afterward is describe the attributes and write the business
logic. Most of its goals open an interactive JavaFX wizard, but the pdo goal can also run
unattended in batch mode.
All goals share the prefix tentackle-wizard, so they can be invoked directly from the command line,
e.g. mvn tentackle-wizard:pdo.
Prerequisites¶
The plugin requires the same JDK and Maven versions as the rest of the framework
(JDK >= 25, Maven >= 3.9.0). Because the wizards are JavaFX applications, the interactive goals
(pdo, operation, browse) need a graphical desktop; the browse goal additionally needs a
reachable Tentackle backend (database or remote server). The init and the batch variant of pdo
run headless.
All goals are aggregator goals and operate on the whole reactor. They are therefore best invoked from the directory of the project's maven parent (the aggregator pom), so that the wizard sees every module and can place the generated files into the correct ones.
Overview of Goals¶
| Goal | Mode | Purpose |
|---|---|---|
pdo |
interactive / batch | Create the source files for a new Persistent Domain Object. |
operation |
interactive | Create the source files for a new Operation (behavior without an entity). |
browse |
interactive | Connect to a backend, browse persisted PDOs and generate test code. |
init |
headless | (Re)install the default code-generation templates into the template directory. |
help |
— | Print plugin usage information (generated by the maven-plugin-plugin). |
How the Wizard Places Files: the Model and Profiles¶
To know where a generated file belongs, the plugin needs two kinds of information.
The model. All goals load the application's
model so the wizard knows which
entities, class IDs, and table names already exist (and can prevent collisions). By default, the model
is read from the dependencies on the plugin classpath (loadModelFromDependencies = true) and from
${project.build.directory}/wurbel/model. The relevant parameters, shared by all goals through the
common base, are:
modelName(tentackle.modelName): the model to load. Defaults to the standard model name.modelDir(tentackle.modelDir): directory holding the model files. Defaults to${project.build.directory}/wurbel/model. Ignored iffilesetsis given.filesets: explicit file sets holding the model, overridingmodelDir.modelDefaults(tentackle.modelDefaults) andentityAliases(tentackle.entityAliases): model defaults and entity aliases to apply while loading, in the same syntax as in the model source.loadModelFromDependencies: also load the model from the resources of the plugin's dependencies (defaulttrue).
Profiles. A profile tells the wizard the target packages and naming for a class of objects.
Almost every Tentackle application groups its entities (e.g., master data vs. transactional data), and
each group typically lives in its own set of packages and its own range of class IDs. You declare one
<profile> per group in the <profiles> configuration; the wizard offers them for selection (or, in
batch mode, picks one per entity by stereotype). Profile names must be unique.
All profiles (for both pdo and operation) share these elements:
name(required): the unique profile name.domainPackage,persistencePackage,domainImplPackage,persistenceImplPackage(required): the target packages for the domain/persistence interfaces and their implementations. Each package must be mapped to exactly one module of the reactor, otherwise the goal fails. This is how the wizard decides which module a file goes into (and a requirement for JPMS since split packages are not allowed in modular projects).domainInterface,persistenceInterface,domainImplementation,persistenceImplementation(optional): override the default super types (DomainObject,PersistentObject,AbstractDomainObject,AbstractPersistentObject) for the generated types.
PdoProfile adds:
pdoPackage(required): the package of the PDO interface.pdoInterface(optional): the super PDO interface, defaults toPersistentDomainObject.minClassId(required) /maxClassId(optional): the range of class IDs reserved for this profile. IDs below 100 are reserved for Tentackle and rejected. See Class IDs below.tablePrefix(optional): a prefix prepended to table names entered in the wizard.
OperationProfile adds:
operationPackage(required): the package of the operation interface.operationInterface(optional): the super operation interface, defaults toOperation.
The pdo Goal¶
This is the main goal. It creates the set of source files for a new PDO:
- the PDO interface (carrying the model comment block),
- the domain interface and the persistence interface,
- the domain implementation and the persistence implementation,
- and, if remoting is enabled, the remote interface and remote implementation.
Each file is written into the directory of the module that owns its package, as derived from the selected profile.
Interactive mode (the default) opens the PDO Wizard, a JavaFX dialog. You pick a profile, enter the entity name, choose the inheritance type and the super entity (if any), the table name, whether caching and remoting are enabled, and a description. The wizard validates the input live against the model — it refuses entity names, class IDs, and table names that already exist, and enforces the rules that follow from the chosen inheritance type (for example, an embedded entity gets no class ID and no caching). The next free class ID is pre-filled from the profile's range.
Batch mode is enabled by configuring batchFilesets. Instead of opening the UI, the goal reads a
secondary model from those file sets and generates the code for every entity it contains that does not
yet exist in the project model. This is handy for bootstrapping a project from an existing schema
(e.g., a model dumped by the tentackle-sql-maven-plugin). Batch parameters:
batchFilesets: the file sets holding the secondary model, in plain model format (as used in the wurbelizer here-docs, or as dumped withdumpAsCommentanddumpVariablesbothfalse). Directories default to the project base directory.- If more than one
PdoProfileis configured, each entity must select its profile via a stereotype matching the profile name (case-insensitive), e.g.#MASTERDATA. batchModelDefaults: model defaults applied to the batch model. Defaults to!ROOT, !ROOTID, !ROOTCLASSID, UNTRACKEDto suppress unwanted entity options, since the dumped model usually already has the project defaults baked in.dumpColumnGap(default2): minimum number of spaces between columns in the generated attribute section of the model source.dumpAnnotationsAsOptions: which annotations to render as attribute options in the generated model source (e.g.@NotNull|, @NotZero;@*matches all, a trailing|matches only parameterless annotations).
At least one PdoProfile must be configured or the goal fails.
The operation Goal¶
The counterpart to pdo for operations —
domain behavior that is not bound to a persistent entity. It opens the Operation Wizard and
generates the operation interface, the domain and persistence interfaces, their implementations, and,
where applicable, the remote layer. Configuration mirrors pdo but uses OperationProfiles; at
least one must be configured. There is no batch mode and no class-ID handling (operations have no
class IDs).
The browse Goal¶
Opens the PDO Browser, which connects to a running backend, lets you navigate the PDOs persisted in the database along their relations, and generates test code (Java fixtures and the corresponding SQL) from the selected objects. It is the tool of choice for building realistic integration-test data from existing records. Parameters:
url(required): the backend URL.user(required) /password: the backend credentials.maxLinesInStringLiteral: caps the number of lines emitted in generated multi-line string literals.mapSchemas(tentackle.mapSchemas): map schema names to flat table names in the generated SQLSELECTstatements.
If no backend can be reached, the goal fails with a clear message.
The init Goal¶
Copies the bundled default templates into the template directory, overwriting any existing files
there. The wizard installs the templates automatically the first time it runs (when the template
directory does not yet exist), so you normally only need init to reset customized templates back to
their defaults.
Templates¶
All generated source is produced from FreeMarker templates. They
live under the templateDir parameter (default ${project.basedir}/templates), organized into two
categories matching the goals: pdo/ and operation/. Each category holds one *.ftl per generated
artifact, e.g. pdo/PdoInterface.ftl, pdo/DomainImplementation.ftl,
operation/OperationInterface.ftl, and so on.
Because the templates are plain files in your project, you can customize them — adjust the license
header, add house-style javadoc, change default imports — and every subsequently generated file will
follow your conventions. Run tentackle-wizard:init to restore the originals.
Class IDs¶
Every root PDO needs a unique, stable class ID used by the persistence layer. The pdo goal manages these automatically:
- Each
PdoProfiledeclares aminClassId(and optionally amaxClassId). WhenmaxClassIdis omitted, the plugin derives the boundaries from the other profiles' ranges, ensuring they do not overlap. - Before each run, the wizard scans the model for the highest class ID already used per profile and pre-selects the next free one.
- To stay consistent across several PDOs generated without an intermediate
mvn clean/wurbel run, the last allocated ID per profile is recorded in a status file under${project.build.directory}/wizard/<profile>.classid. Because this lives undertarget, it is cleaned bymvn clean.
If a profile runs out of free class IDs, the goal warns; reserved IDs below 100 are rejected.
Example Configuration¶
<plugin>
<groupId>org.tentackle</groupId>
<artifactId>tentackle-wizard-maven-plugin</artifactId>
<version>${project.version}</version>
<configuration>
<profiles>
<profile>
<!-- a PdoProfile -->
<name>masterdata</name>
<pdoPackage>com.example.app.pdo</pdoPackage>
<domainPackage>com.example.app.domain</domainPackage>
<persistencePackage>com.example.app.persistence</persistencePackage>
<domainImplPackage>com.example.app.domain.impl</domainImplPackage>
<persistenceImplPackage>com.example.app.persistence.impl</persistenceImplPackage>
<minClassId>1000</minClassId>
<maxClassId>1999</maxClassId>
<tablePrefix>md_</tablePrefix>
</profile>
</profiles>
</configuration>
</plugin>
With this in place:
# scaffold a new PDO interactively
mvn tentackle-wizard:pdo
# scaffold a new operation interactively
mvn tentackle-wizard:operation
# browse a backend and generate test code
mvn tentackle-wizard:browse -Durl=jdbc:postgresql://localhost/appdb -Duser=app
# restore the default templates
mvn tentackle-wizard:init
Run these from the aggregator (parent) directory so the wizard can place files into all modules.
How It Fits Into the Workflow¶
The wizard is a one-shot authoring tool, not part of the regular build lifecycle:
tentackle-wizard:pdo/:operation— scaffold the source files for a new domain object.- You fill in the attributes in the model comment block and add the business logic.
- The normal build (
tentackle:analyze→ wurbelizer → compiler) then generates the persistence mappings and SQL from that model, exactly as described in the Tentackle Maven Plugin documentation.