Skip to content

Jetty 12.1 EE 11 support (jetty12ee11) and container updates - #340

Merged
boris-petrov merged 6 commits into
gretty-gradle-plugin:masterfrom
codeconsole:container-updates
Oct 12, 2026
Merged

boris-petrov merged 6 commits into
gretty-gradle-plugin:masterfrom
codeconsole:container-updates

Conversation

@codeconsole

Copy link
Copy Markdown

This adds a Jetty container for Jakarta EE 11, updates the default container versions, corrects the WebSocket API that Gretty puts on the compile classpath for Tomcat, and fixes a mixed-version Jetty classpath when a Jetty 12 version is overridden. Each change is its own commit.

Add a jetty12ee11 container

jetty12 deploys webapps to Jetty's ee10 environment (Servlet 6.0), including when jetty12Version is set to a 12.1 release. So no Jetty container matched tomcat11's Servlet 6.1. One side effect: jettyRun and the other Jetty tasks in a tomcat11 project found no Jetty with the same servlet API, logged "Cannot find jetty container with compatible servlet-api", and fell back to jetty11.

The new jetty12ee11 container uses Jetty 12.1.13 with the ee11 environment, Servlet 6.1.0 and WebSocket 2.2.0. Its versions can be overridden with jetty12ee11Version, jetty12ee11ServletApiVersion and jetty12ee11WebsocketApiVersion. jetty12 stays as it is (ee10, Jetty 12.0.x).

  • Jetty 12.1 ships ee10 and ee11 with the same API under different package names. So gretty-runner-jetty12ee11 doesn't copy the Jetty 12 runner: it compiles gretty-runner-jetty12's sources with org.eclipse.jetty.ee10 replaced by org.eclipse.jetty.ee11, and the two runners can't drift apart.
  • Both Jetty 12 containers are now created by createJetty12Config(name, environment, ...), the same way createTomcatConfig creates both Tomcats.
  • The container description now includes the environment, e.g. "Jetty 12.1.13 (ee11) started and listening on port 8080". Without it, jetty12 pinned to 12.1 and jetty12ee11 would log the same version.
  • The Jetty integration tests that list their containers (testJettyServerConfig, testJettyContextConfig, testJettyRandomPorts) now include jetty12ee11, and the two with a jetty12-env.xml get a jetty12ee11-env.xml. Tests that don't list containers already run on every container, so they pick up jetty12ee11 automatically.

Behaviour change for tomcat11 projects: their Jetty tasks (jettyRun etc.) now run on jetty12ee11 instead of falling back to jetty11. If such a project has a generic jetty-env.xml written for Jetty 11 (org.eclipse.jetty.webapp.WebAppContext), it is now applied to the EE 11 context, so it needs updating, or the task can be pinned back with jettyRun { servletContainer = 'jetty11' }. In the other direction, a jetty12ee11 project's Tomcat tasks run on tomcat11.

Use Jetty's hidden and protected class matchers

The EE 11 environment doesn't have WebAppContext.addServerClassMatcher / addSystemClassMatcher, so the Jetty 12 runner now uses addHiddenClassMatcher / addProtectedClassMatcher, which Jetty added in 12.0.9 when it renamed server and system classes. In Jetty 12.0.39 the old methods only delegate to the new ones, so jetty12 behaves the same. The cost is that a build pinning jetty12Version below 12.0.9 (May 2024) would need to raise it. No Gretty release has defaulted to a Jetty older than 12.0.29.

Keep every Jetty module on the chosen Jetty 12 version

The Jetty 12 runner configuration forced a list of Jetty modules to the configured version. The runners also depend on jetty-slf4j-impl and the websocket-jetty-server module, which weren't on the list. With the version overridden, those two stayed at the runner's own Jetty version and pulled jetty-util, jetty-io, jetty-http and others along with them. For example, overriding jetty12ee11Version to 12.1.12 left jetty-util at 12.1.13 under jetty-server 12.1.12. Jetty releases all of its modules together, so every org.eclipse.jetty* module now goes to the chosen version instead of a list. org.eclipse.jetty.toolchain is versioned separately and left alone. The default versions resolve exactly as before.

Provide the WebSocket API version each container implements

grettyProvidedCompile adds the container's WebSocket API to the webapp's compile classpath, and both Tomcat versions were a spec level behind:

Container Implements Was Now
tomcat10 (Tomcat 10.1) Jakarta EE 10 2.0.0 2.1.0
tomcat11 Jakarta EE 11 2.1.0 2.2.0

jetty11 (2.0.0) and jetty12 (2.1.0) were already right. These versions were written into ServletContainerConfig. They now live in gradle.properties next to each servlet API version, and a build can override them as <container>WebsocketApiVersion, the same way it overrides <container>ServletApiVersion.

Update Jetty 12, Tomcat 10, Tomcat 11 and ASM

  • Jetty 12.0.29 → 12.0.39
  • Tomcat 10.1.49 → 10.1.60
  • Tomcat 11.0.13 → 11.0.26
  • ASM 9.9 → 9.10.1

ASM has to move with Jetty. The runner configurations force asm to asm_version, and Jetty 12.0.39 and 12.1.13 are both built against ASM 9.10.1, so leaving 9.9 would downgrade the ASM that Jetty's annotation scanning uses.

Check that the Jetty config files are applied

testJettyContextConfig, testJettyRandomPorts and testJettyServerConfig request whatever context path and port the server reports, and the text they check is static HTML. So they passed even when the container's jetty-env.xml or jetty.xml wasn't applied. They now also check the context path (/abc) and port (7777) those files set. I confirmed that removing jetty12ee11-env.xml makes testJettyContextConfig fail on jetty12ee11, while the existing checks still passed.

Testing

  • ./gradlew build with JDK 17 and Gradle 7.6.6.
  • The integration tests (testAll) on all five containers: jetty11, jetty12, jetty12ee11, tomcat10 and tomcat11, on macOS with JDK 17. Two Geb failures were Firefox problems, not Gretty ones, and passed when re-run: once Firefox didn't start (helloGretty, tomcat11), and once its TLS handshake with the generated certificate failed (testJettyRandomPorts HTTPS, jetty11; it then passed three runs in a row).
  • A downstream project (SiteMesh's servlet and Struts examples) on tomcatRun and jettyRun. Its tomcat11 webapps run on Tomcat 11.0.26, and jettyRun now picks jetty12ee11 without the jettyRun override those projects needed before.

Jetty 12.0.29 -> 12.0.39, Tomcat 10.1.49 -> 10.1.60 and
Tomcat 11.0.13 -> 11.0.26 are the latest releases of each line.

ASM moves with Jetty: the runner configurations force asm to
asm_version, and Jetty 12.0.39 is built against ASM 9.10.1, so leaving
it at 9.9 would downgrade the ASM that Jetty's annotation scanning uses.
grettyProvidedCompile puts the container's servlet and WebSocket APIs
on the webapp's compile classpath. The WebSocket API versions were
literals, and both Tomcat ones were a spec level behind:

  tomcat10 (Tomcat 10.1, Jakarta EE 10): 2.0.0 -> 2.1.0
  tomcat11 (Tomcat 11, Jakarta EE 11):   2.1.0 -> 2.2.0

jetty11 (2.0.0) and jetty12 (2.1.0) were already right.

Move the versions into gradle.properties next to each container's
servlet API version and expose them the same way, as
<container>WebsocketApiVersion project properties, so a build can
override them like it can <container>ServletApiVersion.
Jetty 12.0.9 renamed server classes to hidden classes and system
classes to protected classes, adding WebAppContext.addHiddenClassMatcher
and addProtectedClassMatcher, which take org.eclipse.jetty.util.ClassMatcher.
The old addServerClassMatcher and addSystemClassMatcher are deprecated
delegates to them that take the ee10 ClassMatcher subclass, and Jetty's
EE 11 environment does not have them at all.

Behaviour is unchanged on the default Jetty 12.0.39. A build that pins
jetty12Version below 12.0.9 would need to raise it.
jetty12 deploys webapps to Jetty's ee10 environment (Servlet 6.0), even
with jetty12Version set to a 12.1 release, so no Jetty container matched
tomcat11's Servlet 6.1. A tomcat11 project's Jetty tasks found no Jetty
with a compatible servlet API, warned, and fell back to jetty11.

jetty12ee11 runs Jetty 12.1.13 with the ee11 environment, Servlet 6.1.0
and WebSocket 2.2.0, overridable as jetty12ee11Version,
jetty12ee11ServletApiVersion and jetty12ee11WebsocketApiVersion. A
tomcat11 project's Jetty tasks now run on it, and a jetty12ee11
project's Tomcat tasks run on tomcat11. jetty12 is unchanged.

Jetty 12.1 ships ee10 and ee11 with the same API under different
packages, so gretty-runner-jetty12ee11 compiles gretty-runner-jetty12's
sources with org.eclipse.jetty.ee10 switched to org.eclipse.jetty.ee11
rather than keeping a copy. Both Jetty 12 containers come from
createJetty12Config, as both Tomcat containers come from
createTomcatConfig, and their descriptions now name the environment
("Jetty 12.1.13 (ee11)"), since jetty12 on 12.1 reports the same
version.

The Jetty integration tests that list their containers include
jetty12ee11, with ee11 context files where they have jetty12 ones.
testJettyContextConfig, testJettyRandomPorts and testJettyServerConfig
request the context path and port the server reports, and the text they
assert is static HTML, so they passed whether or not the container's
jetty-env.xml or jetty.xml was applied. Assert the context path (/abc)
and port (7777) those files set, so a missing or unread file fails the
test.
The Jetty 12 runner configurations forced a list of Jetty modules to
jetty12Version / jetty12ee11Version, but the runners also depend on
jetty-slf4j-impl and the websocket-jetty-server module, which were not
forced. With the version overridden, those stayed at the runner's own
Jetty version and pulled jetty-util, jetty-io, jetty-http and others
along, so the classpath mixed two Jetty releases: overriding
jetty12ee11Version to 12.1.12 left jetty-util at 12.1.13 under
jetty-server 12.1.12.

Jetty releases all of its modules together, so put every
org.eclipse.jetty* module on the chosen version instead of listing
them. org.eclipse.jetty.toolchain is versioned separately and is left
alone.
@boris-petrov

Copy link
Copy Markdown
Member

Looks great, tests are passing, thanks! Also thank you for the detailed explanations! I'll release this soon, most likely next week.

@boris-petrov
boris-petrov merged commit 5d4384c into gretty-gradle-plugin:master Oct 12, 2026
5 checks passed
@boris-petrov

Copy link
Copy Markdown
Member

Released, thanks @codeconsole!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants