Setup Java Spring Boot Poms

This documentation was generated with the assistance of AI. Please report any inaccuracies.

Generates (or updates, announcing which) the whole multi-module build for a DDD/hexagonal Spring Boot service, in the language and build tool the springboot-stack.yml manifest records: a Maven reactor (root pom.xml holding every dependency and plugin version, plus one pom.xml per module) for Java or Kotlin, or a Gradle Kotlin DSL multi-project build for Kotlin, together with the shared static-analysis configuration the build references.

Purpose

Which build is written depends on the manifest’s project.language (java/kotlin) and project.buildTool (maven/gradle); absent fields mean Java on Maven, regenerated exactly as before. Java with Gradle is invalid and stops the skill.

Language Build tool What is written

java

maven

Maven reactor with the Java toolchain (Lombok, MapStruct, Checkstyle, PMD, SpotBugs, Javadoc).

kotlin

maven

The same reactor with the Kotlin deltas: kotlin-maven-plugin (spring/jpa/all-open compiler plugins, -Xjsr305=strict, mixed Java/Kotlin source roots with default-compile rebound after kotlinc), detekt, ktlint and Dokka instead of Checkstyle/PMD/SpotBugs/Javadoc; MockK and springmockk; detekt.yml and .editorconfig.

kotlin

gradle

settings.gradle.kts, gradle.properties, gradle/libs.versions.toml, a build-logic/ included build with the iru.kotlin-library, iru.spring-boot-app, iru.quality, iru.integration-test and iru.coverage convention plugins, one build.gradle.kts per module, a root build with Dokka aggregation and Sonar, a coverage project using jacoco-report-aggregation, and the Gradle wrapper.

iru-setup-java-springboot-pom exists to make the hexagonal architecture enforceable by the build rather than by convention. Two rules govern everything it writes:

  • Every version lives in one place. On Maven that is the root pom.xml: module poms declare groupId/artifactId only, resolving through the root’s dependencyManagement and pluginManagement. On Gradle it is gradle/libs.versions.toml, with the Spring Boot BOM applied through platform(). A version anywhere else is treated as a defect, and the verification step checks for exactly that.

  • Starter and driver artifact names come from the Spring Initializr reference pom, never from memory, because they change across Boot major versions.

It enforces Java 21 through maven.compiler.release, java.version, and a maven-enforcer-plugin requireJavaVersion [21,) rule, and enforces the module dependency direction through a per-module bannedDependencies rule — domain may not see Spring or any outer module, application may not see infrastructure or api, no infrastructure module may see a sibling, and api may not see infrastructure. boot is the composition root and bans nothing.

The full report/quality plugin set is wired with generated sources excluded from every analysis: Javadoc, Checkstyle, PMD, SpotBugs, Surefire (unit, *Test), Failsafe (integration, *IT), JaCoCo per module plus a report-aggregate in a dedicated coverage module, JXR for cross-referenced source, Maven Site as the aggregator, groovy-maven-plugin writing build-info.properties into boot, and sonar-maven-plugin (Kotlin swaps Javadoc/Checkstyle/PMD/SpotBugs for Dokka/detekt/ktlint). On Gradle there is no enforcer, so the boundaries are guarded by the declared project(":…​") dependencies plus the ArchUnit test written by iru-setup-java-springboot-modules.

Plugin

Shipped by the iru-springboot plugin of the ai-catalog marketplace (install with /plugin install iru-springboot@ai-catalog; see Plugins).

Invocation

/iru-setup-java-springboot-pom
stack-file: springboot-stack.yml
initializr-pom: <path>
mode: new|existing
on-existing: ask|keep|update|replace

The second form (with args lines) is how iru-setup-java-springboot calls it.

Inputs

Argument Required Description Default

stack-file

No

args key: value line giving the path to the manifest written by iru-setup-java-springboot. Read in full for the project identity (including project.language, project.buildTool and project.kotlinVersion), concurrency model, technology list, the top-level sonar block (mode: cloud | self-hosted | none plus organization/projectKey/hostUrl), and frontend (none/hilla). A manifest with no sonar key, or frontend: none/absent, is treated as cloud/no-Hilla for backward compatibility. If the file doesn’t exist the skill stops and points the user at /iru-setup-java-springboot — it deliberately does not re-interview.

springboot-stack.yml at the repository root

initializr-pom

No

args key: value line giving the path to the reference build fetched from Spring Initializr: a pom for Maven, or the starter’s build.gradle.kts for Kotlin + Gradle. If absent, the skill fetches it itself from the manifest’s initializr.dependencies (Kotlin adds language=kotlin; Gradle downloads and unzips starter.zip) and confirms an XML response rather than a plain-text error.

Fetched fresh from https://start.spring.io/pom.xml

mode

No

args key: value line, new or existing. Informational only: scratch-vs-update is decided per file from what is on disk, and mode: existing does not mean "update silently".

None

on-existing

No

args key: value line, ask, keep, update or replace. Applied to every pre-existing file without asking (the warning is still printed).

ask

Existing files handling

No

The skill says whether it is generating the reactor from scratch or updating an existing one, listing which of the root pom, module poms, checkstyle.xml and spotbugs-exclude.xml (Java), detekt.yml and .editorconfig (Kotlin), or the Gradle settings, catalog, root build, build-logic/, module build files and wrapper exist. A build tool switch (a pom.xml where the manifest says gradle, or the reverse) is not an update: Stop is recommended, and Replace never deletes the old build. For each it warns, states where the file disagrees with the manifest, and asks Update (merge; unknown dependencies, plugins, profiles and properties are preserved and listed in the report), Keep as is (recommended for checkstyle.xml and spotbugs-exclude.xml), Replace, or Stop (root pom or settings.gradle.kts question only; recommended when the existing root pom is not pom-packaged). Module poms may be asked as one grouped question.

None — user must choose

Outputs

  • Root pom.xml — the Spring Boot parent, the module list, all version properties, every BOM import copied from the reference pom, dependencyManagement for the project’s own modules, project-wide dependencies, and the full build/reporting plugin configuration. pluginManagement also version-manages the code and documentation generators that Setup Java Spring Boot APIs wires into individual modules — the OpenAPI, protobuf, GraphQL-codegen and AVRO plugins, plus frontend-maven-plugin for the AsyncAPI documentation generators — along with the asyncapi.docs.skip property that lets an offline build opt out of the npm-based documentation step. The GraphQL codegen version is shared with the graphql-java-codegen runtime artifact that generated GraphQL client code extends, so the two cannot drift apart. The sonar.* properties and the sonar-maven-plugin entry are written only when the manifest’s sonar.mode isn’t none (even if ci.enabled is false, in which case an XML comment notes that no CI step sends reports), with sonar.host.url resolved per mode (SonarCloud for cloud, the manifest’s host for self-hosted) and sonar.organization omitted for self-hosted unless the manifest set one. When the manifest’s frontend is hilla, the root pom additionally gains a vaadin.version/vaadin.skip property pair, a vaadin-bom dependencyManagement import, a vaadin-maven-plugin pluginManagement entry, and a production profile (vaadin.productionMode=true) — all four omitted otherwise; see Setup Java Spring Boot Hilla for how a module is wired against these pins.

  • One pom.xml per module named in the manifest, plus the intermediate aggregator poms (infrastructure/, infrastructure/database/, infrastructure/clients/, api/). Each infrastructure/clients/<name> additionally carries, at test scope, the Testcontainers module for whichever API mock stack.apiMock names, so that module’s own *IT can start just the mock instead of the whole compose stack.

  • coverage/pom.xml — JaCoCo report-aggregate across every module, declared last in the reactor so every module’s execution data already exists when it runs.

  • boot/pom.xml — additionally carrying spring-boot-maven-plugin and the groovy-maven-plugin build-info step.

  • Kotlin on Maven: Kotlin-specific root pom properties (kotlin.version as recorded in the manifest, i.e. the version Spring Boot manages, MockK, springmockk, detekt, ktlint, Dokka), src/main/kotlin/src/test/kotlin .gitkeep placeholders in every jar module (unless sonar.mode is none), and root detekt.yml and .editorconfig.

  • Kotlin on Gradle: settings.gradle.kts, gradle.properties, gradle/libs.versions.toml, root build.gradle.kts, the build-logic/ included build with five convention plugins, one build.gradle.kts per leaf module (aggregator directories get none), detekt.yml, .editorconfig, and the Gradle wrapper (copied from the Initializr starter, a local gradle, or Docker, never hand-written).

  • checkstyle.xml and spotbugs-exclude.xml at the repository root (Java), if absent (an existing one follows the Step 0 answer, Keep by default; on Update the generated-source matches are added to spotbugs-exclude.xml if missing).

  • A report stating whether the reactor was generated from scratch or updated, the action per file (created / updated / replaced / kept as is, with each mismatch left in a kept file), and listing the reactor’s build order, every version pinned (separating those copied from the reference pom from those looked up on Maven Central), which module each significant dependency landed in, anything that couldn’t be placed, any hexagon violation found, a note when Sonar is configured but ci.enabled is false, how sonar.mode was wired (none, cloud, or self-hosted, with the resolved host/organization/project key), and how frontend was wired (none, or hilla with the resolved vaadin.version).

The generated files' bytes come from template files under templates/ (and, where a template needs variant-specific notes, reference/) in .claude/skills/iru-setup-java-springboot-pom/; the skill reads only the files for the variant it resolved, not the whole set, which keeps its SKILL.md small.

Execution flow

flowchart TD A["Start /iru-setup-java-springboot-pom"] --> B["Step 0: Read the manifest\n(language, build tool, Kotlin version);\nfetch or read the Initializr reference build"] B -- manifest missing or Java with Gradle --> STOP["Stop: run /iru-setup-java-springboot"] B --> C["Classify every extracted dependency\nto its owning module"] C -- pre-existing build files --> D{"Per file: Update /\nKeep as is / Replace / Stop?\n(or on-existing)"} D -- stop at root build file --> STOP2["Stop; report"] D -- update, keep or replace --> T C -- from scratch --> T{"Language and build tool?"} T -- "Java + Maven" --> E["Step 1: Root pom\n(versions, plugins, enforcer,\nSonar and Hilla wiring)"] T -- "Kotlin + Maven" --> E E -- Kotlin --> EK["Step 1K: Kotlin deltas\n(kotlin-maven-plugin, detekt,\nktlint, Dokka, MockK)"] E --> F["Steps 2-3: Place dependencies;\nwrite each module pom with no versions\nand its bannedDependencies rule"] EK --> F F --> G["Step 4: Write every pom to disk\n(Kotlin: source root placeholders)"] G --> H["Step 5: Write analysis config:\ncheckstyle.xml, spotbugs-exclude.xml\nor detekt.yml, .editorconfig"] T -- "Kotlin + Gradle" --> GR["Step 2 placement, then Step 5G:\nsettings, catalog, build-logic,\nmodule build files, wrapper"] GR --> H H --> I["Step 6: Verify via iru-gate-runner:\nvalidate and dependency:tree,\nor gradlew help, build, dependencies"] I -->|"version outside the single\nversion file, or unmanaged conflict"| J["Move or pin it in the root pom\nor version catalog"] J --> I I --> K["Step 7: Sanity-check the hexagon"] K --> L["Step 8: Report versions, placements,\nand any deliberate violation"]

Dependencies

Invokes

None — it reads springboot-stack.yml and the Spring Initializr API and writes the build files itself. Its only delegation is to the iru-gate-runner agent for verification (see Related agents).

Invoked by

Receives mode, and on-existing only when that arrived in the orchestrator’s own args. If the root pom is kept as is but is not a usable pom-packaged reactor, the bootstrap stops there. Also runs standalone (/iru-setup-java-springboot-pom) to regenerate or update the reactor from an updated manifest.

  • iru-gate-runner — spawned for Step 6’s verification (Maven validate and dependency:tree, or the Gradle wrapper’s help, build and dependencies runs), since a multi-module log is exactly the kind of output that shouldn’t land in the caller’s context.

Source

SKILL.md on GitHub — the file this page was generated from.