Skip to content

[FEATURE] Add first-class EE8 (javax.servlet) modules to JGit #272

Description

@davido

Description

Add first-class EE8 (javax.servlet) modules to JGit, alongside the
canonical jakarta.servlet modules — org.eclipse.jgit.http.server.ee8,
org.eclipse.jgit.lfs.server.ee8, and their test modules — so downstream
consumers that cannot migrate to jakarta.servlet can keep tracking JGit
master.

The modules are generated from the canonical sources: only the servlet
imports are rewritten (jakarta.servletjavax.servlet, Jetty EE10 → EE8),
with the original Java package names and source line numbers preserved.
Apart from being generated, they get the full first-class treatment:

  • Both toolchains — Bazel (a shared, sed-based servlet-flavour transform
    from bazlets, @com_googlesource_gerrit_bazlets//tools; no added external
    dependency) and Maven (copy-and-rewrite reactor).
  • Real OSGi bundlesMETA-INF/MANIFEST.MF importing javax.servlet,
    plus Eclipse PDE project files.
  • Tested — a Bazel generated_srcs_test (derivation, line-count
    preservation, no jakarta residue) and the EE8 Maven reactor tests; both run
    the HTTP/LFS suites against the generated EE8 jars.
  • IDE-debuggable — the generated source jar attaches to the EE8 binary jar;
    breakpoints in the running javax.servlet classes bind correctly (verified
    live in Eclipse and IntelliJ).

This mirrors Jetty 12's own EE8 + EE10 dual model.

It is deliberately minimally invasive: the canonical production servlet
modules and sources are untouched, original package names are kept (zero import
churn for consumers), and there is no change to the JGit p2 update site. The
Bazel transform carries no per-repo data — it selects only the to_javax
direction of the shared bazlets toolchain.

The one restriction — no Tycho/p2 publishing. The EE8 modules keep the same
exported packages (same class FQDNs) as the canonical ones, so the two must
never share a classpath. They are therefore intentionally not added to the
JGit features, the p2 repository, or the target platform. Because p2 is off the
table, Bazel and Maven are the delivery channels: Bazel for source consumers
(Gerrit builds JGit from source), Maven for build/test and the artifact shape
needed for future binary (Maven Central) publication.

Motivation

JGit master ships its servlet-facing modules on jakarta.servlet
(Servlet 6 / Jetty 12 EE10). Major downstreams — Gerrit Code Review, Gitiles
and the Gerrit plugin ecosystem
— still run on javax.servlet (Servlet 4 / Jetty 12
EE8) and cannot move to jakarta.servlet yet.

For Gerrit's stable branches the blocker is concrete: the incompatibility lies
along two orthogonal axes.

  • Servlet namespace — Gerrit stable-3.12/stable-3.13 are javax.servlet
    (Servlet 4 / Jetty 12 EE8), while JGit master and stable-7.4 are
    jakarta.servlet.
  • Build system — Gerrit stable still uses WORKSPACE, while JGit master and
    the master-tracking javax.servlet branch (servlet-4) use bzlmod.

Each candidate JGit branch satisfies only one axis — stable-7.4 is WORKSPACE
but jakarta, servlet-4 is javax but bzlmod — so Gerrit stable, which needs
javax on WORKSPACE, has no JGit branch that fits today.

The goal is to close this gap so the JGit submodule can be bumped on the
supported Gerrit releases (stable-3.12/stable-3.13) to JGit stable-7.4.

Gitiles has already been adapted to consume the JGit EE8 servlet bridge, which
validates the approach end to end; Gerrit and its stable branches still need
the same first-class EE8 artifacts from JGit.

The consequences today:

  • Gerrit cannot consume JGit master as-is, because JGit master is
    jakarta.servlet-only.
  • A separate servlet-4 JGit branch is not sustainable — it would never be a
    stable release line and would demand constant merge work.
  • The resulting stale JGit submodule on stable-3.12/stable-3.13 holds
    back picking up JGit fixes and features downstream.

Without first-class EE8 modules in JGit, every javax.servlet consumer is
forced into either an out-of-tree rewrite (reverted once already — see
Alternatives) or an unmaintainable fork. First-class, generated EE8 modules
let all of them track JGit master directly.

Options analysis for the stable-branch maintenance problem:
https://davido.github.io/gerrit-jgit-maintenance/

Alternatives considered

  • Gerrit-local on-the-fly rewrite — the earlier attempt (Ivan Frade,
    https://gerrit-review.googlesource.com/c/gerrit/+/446221). It rewrote JGit's
    servlet code downstream at build time. Reverted by Matthias Sohn
    (https://gerrit-review.googlesource.com/c/gerrit/+/447822), "only works in
    bazel build but breaks the build in Eclipse."
    It was also untested at the
    IDE/generation level and lived only downstream, so every consumer would need
    its own copy. This proposal addresses that revert reason directly: the
    generated EE8 modules build in Bazel and Maven, attach sources and debug in
    Eclipse and IntelliJ, and carry a generation test.

  • A long-lived servlet-4 JGit branch — unsustainable: never a stable release
    line, perpetual merge work to keep it current with master.

  • Copying the servlet code into a parallel EE8 tree — ~6,500 LoC plus
    duplicated tests to hand-maintain in lockstep with the canonical modules.
    Rejected in favour of generation, which keeps EE8 a mechanical transform of the
    canonical sources (same line numbers, no logic to drift).

  • Relocating to org.eclipse.jgit.*.ee8 packages (which would be
    p2-co-installable alongside the canonical modules) — rejected: it breaks the
    simple import-only generation and forces every consumer to change its
    imports
    . Keeping the same FQDNs is deliberate; the only cost is that the EE8
    modules can't be published to p2 (they'd collide with the canonical ones), and
    Bazel + Maven cover the consumers that need them.

Additional context

A complete JGit implementation is already up for review, under topic
ee8-servlet-bridge.

Verification status:

  • Bazel: generated_srcs_test, http.test.ee8:http,
    lfs.server.test.ee8:lfs_server → all pass.
  • Maven (Java 17): EE8 reactor testBUILD SUCCESS, 293 tests,
    0 failures.
  • Review CI: use the public review systems as the source of truth for
    current status; companion changes may need re-verification after prerequisite
    bazlets/JGit pins are published.

Usable today. Where no officially supported Gerrit build with an updated
JGit exists yet, Gerrit can be built directly from the
Gerrit stable companion change,
which already pins the JGit submodule to the current stable-7.4 tip plus the
single commit that adds the EE8 bridge — so you get the latest stable-7.4 JGit
with the bridge out of the box, no manual JGit bump.

The canonical production servlet modules and sources are untouched — the EE8
modules are additive; the only canonical-source change is a shared junit.http
test-helper refactor (extracting an AppServerBase) so the EE8 test module can
reuse it.

Shared transform toolchain. The Bazel source transform, the JUnit-suite
macro, and the generated-sources checker live once in bazlets
(@com_googlesource_gerrit_bazlets//tools) as a dependency-free sed
package-prefix rewrite. JGit selects the to_javax direction. (It can equally
be vendored in-tree under tools/jgit-ee8 if the project prefers no bazlets
dependency.)

Adjacent ecosystem already migrated (mirroring the Gerrit companion; not
part of this request
, listed to show the EE8 bridge works end to end for real
consumers):

  • Gitiles — adapted to consume the JGit EE8 servlet bridge ("Move Gitiles
    off JGit servlet-4 via EE8 bridge"
    ): its //lib:jgit-servlet now resolves to
    the generated jgit-servlet-ee8 module; servlet tests pass.
  • Gerrit LFS plugin — migrated to the JGit EE8 servlet bridge (a
    Bazel-9/Bzlmod build modernization commit, then the EE8 swap); plugin build
    and tests pass.

Bigger picture (future goal — not part of this request). JGit master is
already EE10 (jakarta.servlet); this request adds the EE8 (javax.servlet)
half, so JGit would ship both flavours from one tree — mirroring Jetty 12. The
same shared transform already runs in the other direction too: Gitiles' EE10
flavour is published for review
(gitiles change 601822).
That dual-flavour Gerrit is described in its own design proposal, up for review
(Gerrit EE8/EE10 flavoured release);
it is motivation only here, not part of this request.

Prior work:

A fuller design write-up exists — the same-FQDN / no-p2 reasoning, the
per-commit breakdown, the verification details, and the alternatives in depth:
JGit EE8 Servlet Bridge — Design Proposal.
Happy to land it wherever best fits the project's process (GitHub Discussion,
project wiki, an in-tree doc alongside tools/jgit-ee8/README.md, or just an
external link).

Links:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions