Skip to content

feat(devloop): run on various application servers (#25851) (CP: 25.3) - #26066

Merged
vaadin-bot merged 2 commits into
25.3from
cherry-pick-25851-to-25.3-1790753312647
Sep 30, 2026
Merged

vaadin-bot merged 2 commits into
25.3from
cherry-pick-25851-to-25.3-1790753312647

Conversation

@vaadin-bot

Copy link
Copy Markdown
Collaborator

This PR cherry-picks changes from the original PR #25851 to branch 25.3.

Original PR description

Fixes #25458

Background — how the loop reaches the application. The dev loop hot
swaps by attaching two -javaagent jars to the JVM the application runs
in and redefining classes through Instrumentation. For a server that
runs inside the build's own JVM, that JVM is Maven's, so MAVEN_OPTS
carries them and there is nothing else to arrange.

Until now the loop could only run an application whose server shared the
build's JVM. It now also runs WildFly, TomEE, Payara Server, Payara
Micro, Open Liberty and Apache Tomcat, which each start a server of
their own, with the agents travelling in a plugin parameter that reaches
the forked JVM. Two fixes and an integration-test fixture come with it.

Context. Nothing on Maven's command line and nothing in its
environment reaches a JVM that Maven forked, so each forked container
needs a channel of its own. Four of them expose one as a user property
and Liberty as a property prefix; Cargo exposes none that any command
line can set, which is why it is the one runtime that cannot work
without the loop's build extension.

  • Added WildFly and TomEE as runtimes, with the JVM flags travelling in
    wildfly.javaOpts and tomee-plugin.args, module options folded into
    one token for WildFly, and backslashes doubled for TomEE alone
  • Added Payara Server and Payara Micro, both on the start goal, never
    dev, whose watcher redeploys in competition with every apply
    • Payara Server's payara.javaCommandLineOptions is a List<String>,
      which Maven splits on commas and the mojo then drops any piece
      without an = in it, so comma-bearing flags travel in a JVM
      argument file instead
  • Added Open Liberty, whose channel is one Maven property per flag
    (liberty.jvm.<key>), with looseApplication forced off so that
    Liberty's own application monitor stops competing with every apply
  • Added Apache Tomcat, driven through Codehaus Cargo, in one entry that
    answers for every container Cargo drives
    • Its flags go on the model as the cargo.jvmargs project property,
      because no parameter of its run goal carries a user property, and
      the build extension appends to a value a project set itself rather
      than replacing it
  • Switched the run goal off for the whole reactor and back on for the
    application's module for Cargo, both Payaras and WildFly: unlike
    Jetty's, their mojos do not skip a project that builds no deployment,
    and failed or blocked the build on the reactor root
    • A forked container now names package across the reactor as well,
      so a sibling module reaches WEB-INF/lib as a jar rather than as a
      directory
  • Gave a forked container a startup window of its own, since
    provisioning a server outruns the time an ordinary boot is given
  • Confirmed a resource against the bytes on the classpath before
    counting it as changed, so a rewritten-but-identical file is no longer
    a change
  • Tried both loopback literals when the application dials the daemon,
    after a Payara Micro boot left the application JVM preferring ::1
    while the daemon listened on 127.0.0.1 and the application ran
    unregistered
  • Moved the agent's Instrumentation handle out of the system
    properties, which WildFly's transactions subsystem read as a string
    and died on
  • Added test-devloop-cargo, a third IT fixture running the shared
    dev-loop ITs against a WAR deployed on Tomcat 11, and wired it into
    the CI matrix
  • Adds a fixture per forked server the dev loop drives, each running the
    shared suite from flow-test-devloop-support in dev-bundle mode, and runs
    them in CI slots 9 and 10. Liberty is served under /devloop, so the ITs
    read a context path from the fixture pom.

Fixes #25458

**Background — how the loop reaches the application.** The dev loop hot
swaps by attaching two `-javaagent` jars to the JVM the application runs
in and redefining classes through `Instrumentation`. For a server that
runs inside the build's own JVM, that JVM is Maven's, so `MAVEN_OPTS`
carries them and there is nothing else to arrange.

Until now the loop could only run an application whose server shared the
build's JVM. It now also runs WildFly, TomEE, Payara Server, Payara
Micro, Open Liberty and Apache Tomcat, which each start a server of
their own, with the agents travelling in a plugin parameter that reaches
the forked JVM. Two fixes and an integration-test fixture come with it.

**Context.** Nothing on Maven's command line and nothing in its
environment reaches a JVM that Maven forked, so each forked container
needs a channel of its own. Four of them expose one as a user property
and Liberty as a property prefix; Cargo exposes none that any command
line can set, which is why it is the one runtime that cannot work
without the loop's build extension.

- Added WildFly and TomEE as runtimes, with the JVM flags travelling in
  `wildfly.javaOpts` and `tomee-plugin.args`, module options folded into
  one token for WildFly, and backslashes doubled for TomEE alone
- Added Payara Server and Payara Micro, both on the `start` goal, never
  `dev`, whose watcher redeploys in competition with every apply
  - Payara Server's `payara.javaCommandLineOptions` is a `List<String>`,
    which Maven splits on commas and the mojo then drops any piece
    without an `=` in it, so comma-bearing flags travel in a JVM
    argument file instead
- Added Open Liberty, whose channel is one Maven property per flag
  (`liberty.jvm.<key>`), with `looseApplication` forced off so that
  Liberty's own application monitor stops competing with every apply
- Added Apache Tomcat, driven through Codehaus Cargo, in one entry that
  answers for every container Cargo drives
  - Its flags go on the model as the `cargo.jvmargs` project property,
    because no parameter of its run goal carries a user property, and
    the build extension appends to a value a project set itself rather
    than replacing it
- Switched the run goal off for the whole reactor and back on for the
  application's module for Cargo, both Payaras and WildFly: unlike
  Jetty's, their mojos do not skip a project that builds no deployment,
  and failed or blocked the build on the reactor root
  - A forked container now names `package` across the reactor as well,
    so a sibling module reaches `WEB-INF/lib` as a jar rather than as a
    directory
- Gave a forked container a startup window of its own, since
  provisioning a server outruns the time an ordinary boot is given
- Confirmed a resource against the bytes on the classpath before
  counting it as changed, so a rewritten-but-identical file is no longer
  a change
- Tried both loopback literals when the application dials the daemon,
  after a Payara Micro boot left the application JVM preferring `::1`
  while the daemon listened on `127.0.0.1` and the application ran
  unregistered
- Moved the agent's `Instrumentation` handle out of the system
  properties, which WildFly's transactions subsystem read as a string
  and died on
- Added `test-devloop-cargo`, a third IT fixture running the shared
  dev-loop ITs against a WAR deployed on Tomcat 11, and wired it into
  the CI matrix
- Adds a fixture per forked server the dev loop drives, each running the
shared suite from flow-test-devloop-support in dev-bundle mode, and runs
them in CI slots 9 and 10. Liberty is served under /devloop, so the ITs
read a context path from the fixture pom.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: mikhail <mikhail@vaadin.com>
Co-authored-by: Mikhail Shabarov <61410877+mshabarov@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

The loop's agents now reach a forked server's JVM, not only Maven's own

flowchart LR
    subgraph Before
        direction TB
        B1["MavenGoalRuntime.invocation()"] -->|jvmFlags into MAVEN_OPTS| B2["Maven's own JVM"]
        B2 -->|DevLoopAgent redefines classes| B3["Jetty app"]
    end
    subgraph After
        direction TB
        A1["MavenGoalRuntime.invocation()"] -->|embedded: jvmFlags into MAVEN_OPTS| A2["Maven's own JVM"]
        A2 -->|DevLoopAgent redefines classes| A3["Jetty app"]
        A1 -->|forked: jvmFlags into -D jvmFlagsProperty| A4["server plugin (new)"]:::changed
        A4 -->|starts, passing the flags| A5["forked server JVM (new)"]:::changed
        A5 -->|DevLoopAgent redefines classes| A6["WildFly / TomEE / Payara / Liberty / Tomcat app (new)"]:::changed
    end
    Before ~~~ After
    classDef changed stroke:#c9a227,stroke-width:3px
Loading

MavenGoalRuntime.invocation() now branches on ServerPlugin.embedded(). For Jetty the -javaagent jvmFlags still travel in MAVEN_OPTS and the app runs in Maven's own JVM. For the forked servers, forkedJvmFlags() instead emits -D<jvmFlagsProperty> on Maven's command line so the plugin passes the flags to the server's own JVM, where DevLoopAgent instruments the app; MAVEN_OPTS carries no agents there (plugin.embedded() ? jvmFlags : List.of()). Mechanism per the pull request description and the code in MavenGoalRuntime/ServerPlugin.

Diagram Bot draws the mechanism this pull request touches; it does not review the change. Verify it against the diff.

Generated by Diagram Bot for issue #26066 · ◷

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

 1 503 files  + 57   1 588 suites  +57   2h 0m 41s ⏱️ + 34m 41s
11 965 tests +108  11 897 ✅ +108  68 💤 ±0  0 ❌ ±0 
12 533 runs  +318  12 465 ✅ +318  68 💤 ±0  0 ❌ ±0 

Results for commit 5598403. ± Comparison against base commit ea7f13b.

♻️ This comment has been updated with latest results.

Comment thread flow-tests/test-devloop/test-devloop-cargo/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-cargo/devloop-app/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-jbosseap/devloop-app/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-jbosseap/devloop-shared/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-jbosseap/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-payara/devloop-shared/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-payara/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-tomee/devloop-app/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-tomee/devloop-shared/pom.xml Outdated
Comment thread flow-tests/test-devloop/test-devloop-tomee/pom.xml Outdated
@vaadin-bot

Copy link
Copy Markdown
Collaborator Author

This PR is eligible for auto-merging policy, so it has been approved automatically. If there are pending conditions, auto merge (with 'squash' method) has been enabled for this PR [Message is sent from bot]

@vaadin-bot
vaadin-bot enabled auto-merge (squash) September 30, 2026 09:56
@sonarqubecloud

Copy link
Copy Markdown

Comment thread flow-tests/test-devloop/test-devloop-cargo/devloop-shared/pom.xml Outdated
@vaadin-bot
vaadin-bot merged commit 9c6d608 into 25.3 Sep 30, 2026
39 checks passed
@vaadin-bot
vaadin-bot deleted the cherry-pick-25851-to-25.3-1790753312647 branch September 30, 2026 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants