Skip to content

Java 21 - prepare first production release#201

Merged
xsalefter merged 20 commits intomasterfrom
java2x
Apr 13, 2026
Merged

Java 21 - prepare first production release#201
xsalefter merged 20 commits intomasterfrom
java2x

Conversation

@xsalefter
Copy link
Copy Markdown
Contributor

@xsalefter xsalefter commented Apr 12, 2026

This PR would be a first milestone for Java 21 work. After this PR, we can expect that killbill-commons:

  1. Use JDK 21 as primary JDK
  2. Use jakarta namespace instead of javax namespace
  3. Use Guice 7.0.0

What's done:

  1. Fork jooby:1.6.9 as one of killbill-commons module
  2. jooby/README.md have general info including what forked from jooby original module(s), and what's not.
  3. jooby/CHANGES.md contains detailed changelog about what changes from original upstream
  4. Migrate all Java EE (servlet, inject, REST) from javax to jakarta
  5. The CI updated to use Java 21, but still use another branch (java21) in gh-actions-shared
  6. The release.yml also get updated to use Java 21.

Once merge, we will release killbill-commons:0.27.0 in maven central.

xsalefter and others added 19 commits April 3, 2026 15:10
Vendor fork of Jooby 1.6.9 (core, servlet, jetty, jackson, funzy) merged into a
single killbill-jooby module. POM written from scratch under Kill Bill Maven
coordinates, merging dependencies from 4 upstream modules. All 172 main source
files and 125 test files imported. Jetty adapter modified for Jetty 10 API
(WebSocketServerFactory removal, SslContextFactory.Server, PushBuilder removal).
20 PowerMock-dependent test files moved to src/test/java-excluded/.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
POM dependencies aligned to Kill Bill managed versions (Guice 5.1.0, Jetty 10,
ASM 9.7, Guava 31.1, Config 1.4.2, SLF4J 2.0.9). Removed PowerMock and
guice-multibindings (merged into core Guice since 4.2). Added jakarta.annotation-api
for @PostConstruct/@PreDestroy. Moved 20 test files that depend on PowerMock to
src/test/java-excluded/ and configured -Pjooby profile to compile/run only the
remaining tests. Default build skips tests entirely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Complete rewrite of MockUnit.java from EasyMock record-replay to Mockito 5 APIs:
mock() replaces createMock(), mockStatic() replaces PowerMock.mockStatic(),
MockedConstruction with pre-mock delegation replaces createMockAndExpectNew().
44 test files migrated with mechanical changes: expect().andReturn() to
when().thenReturn(), expectLastCall() removed, RunWith/PrepareForTest removed.
Manual fixes for RequestTest (sequential returns), JacksonParserTest (overload
disambiguation), OptionsHandlerTest (varargs helper), SseTest (doAnswer captors).
Surefire configured with reuseForks=false for ByteBuddy stability.

Result: 661 tests pass, 0 failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Static mock conversion: unit.mockStatic(X.class); when(X.method()).thenReturn()
becomes unit.mockStatic(X.class).when(() -> X.method()).thenReturn(). CookieImplTest
and RequestLoggerTest rewritten to avoid mocking java.lang.System (Mockito cannot
mock it due to classloader interference). JettyResponseTest and DefaultErrHandlerTest
converted void captures to doAnswer() with AtomicReference. ServletServletResponseTest
changed partialMock(FileChannel) to mock() to avoid NPE from CALLS_REAL_METHODS.

Result: 751 tests pass, 0 failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Constructor mock conversion using MockUnit.mockConstructor() with pre-mock
delegation pattern. Added preMockToConstructed reverse map in MockUnit to resolve
identity mismatches when tests compare unit.get() results with constructed objects.
WebSocketImplTest: 7 void captures converted to doAnswer(). WsBinaryMessageTest:
identity assertions replaced with assertNotNull+isMock() since MockedConstruction
returns different objects than pre-mocks.

Result: 807 tests pass, 0 failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MockUnit enhanced with addVoidCapture()/voidCaptures map for doAnswer-based void
method capturing, setAccessible(true) for package-private inner classes, and
matcher cleanup in mockConstructor(). 4 internal tests + JoobyTest (44 tests,
3000 lines) migrated. Key Mockito limitations discovered: MockedStatic.when()
leaks stubbing state from preceding void calls, Runtime.availableProcessors() is
native/unmockable, void methods with matchers are orphaned outside doX() context.
JoobyTest required 46 toInstance() void captures converted to doAnswer pattern
and ~30 void-with-matcher calls removed entirely.

CHANGES.md updated with full migration details. README.md updated with test counts
(894 tests, 103 files). Migration tracker finalized.

Result: 894 tests pass, 0 failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…syMock

Added Apache HttpClient 4.5.14 (httpclient, httpcore, fluent-hc, httpmime) as
test-scope dependencies for integration test Client.java. Restored 4 integration
test utilities (JoobyRunner, JoobySuite, Client, ServerFeature) from java-excluded.
SseFeature deferred (hardwired to Ning AsyncHttpClient, not used in Kill Bill).
Migrated last 2 EasyMock holdouts (ParamConverterTest, MutantImplTest) which only
used createMock(). Removed easymock dependency from pom.xml. mockito-core is now
the sole test mock framework.

Result: 894 tests pass, 0 failures. 6 files remain in java-excluded (non-mock blockers).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ions

Response.Forwarding.setResetHeadersOnError() called this.setResetHeadersOnError()
instead of rsp.setResetHeadersOnError() causing infinite recursion. Upstream Jooby
1.6.9 copy-paste error: every other Forwarding method delegates to rsp. Bug is
latent since no code calls setResetHeadersOnError() through a Forwarding wrapper.
SpotBugs blanket suppression replaced with targeted exclusions for 77 upstream
findings across 12 bug patterns (mutable state exposure in internals, loose JSR-305
annotations, cleanup-path return values). Zero findings remain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jackson-annotations was declared at compile scope but only directly imported in
Issue1087.java (JsonView test). Kill Bill does not use JsonView, a niche Jackson
feature for selective field serialization. The core JacksonRenderer rendering path
is already covered by JacksonRendererTest. Removing both the test and the dependency
eliminates a dependency:analyze false positive without any regression risk.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two CodeQL-flagged exponential backtracking vulnerabilities in upstream Jooby 1.6.9:

RoutePattern.java: nested quantifier (?:[^/]+)+? in :var group allowed ambiguous
splitting of non-slash characters across repetitions. Collapsed to [^/]+. Inner
[^/]+? inside curly-brace groups could match closing braces creating ambiguous
paths. Restricted to [^/}]+. Verified semantically equivalent on all route forms.

PemReader.java: alternation (?:\s|\r|\n)+ created ambiguous matching since
\s already includes \r and \n. Simplified to \s+. Applies to both CERT
and KEY patterns (code borrowed from Netty).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fork `jooby:1.6.9` as new modules in `killbill-commons`
Restore the deferred Jooby tests into the active test tree and remove the
one-off migration scaffolding around them.

- restore FileConfTest, LogbackConfTest, RequestScopeTest,
  JettyHandlerTest, JettyServerTest, and SseFeature
- delete the obsolete 1-7-easymock-migration note
- remove the dedicated Jooby Maven profile and refresh README/CHANGES

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- #195: CsrfHandler no longer echoes the attacker token
- #196: Cookie.Signature uses an explicit UTF-8 charset
- #197: SSIHandler reads the managed stream and reports the include path
- fold in the follow-up CsrfHandlerTest import cleanup

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the remaining commons modules that use injection annotations onto the
Jakarta namespace.

This updates queue, jdbi, metrics, and the vendored Jooby fork while keeping
the shared dependency management aligned with the Guice 7 baseline.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Complete the remaining namespace moves that sit on top of the inject upgrade.

- migrate automaton and xmlloader from javax.xml.bind to jakarta.xml.bind
- move the Jooby servlet adapter and related tests to jakarta.servlet
- move Jooby's direct annotation usage to jakarta.annotation
- migrate the metrics and skeleton web layers to the Jakarta servlet stack

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collect the newly introduced Jakarta-era version properties in the root pom
and keep the Jooby module documentation aligned with the maintained fork
baseline.

This keeps the version pins easier to audit while the parent pom still needs
follow-up alignment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pierre pierre requested a review from Copilot April 12, 2026 08:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR prepares the first Java 21 production-ready release of killbill-commons by vendoring Jooby 1.6.9 as killbill-jooby, migrating Java EE APIs to jakarta.*, and updating build/CI/release tooling to target JDK 21.

Changes:

  • Add and document the killbill-jooby fork (upstream provenance + maintained deltas + Maven module wiring).
  • Migrate key APIs from javax.* to jakarta.* (servlet/inject/JAXB) and align dependencies (Guice 7, Jetty 11, etc.).
  • Update GitHub Actions workflows and module POMs for the 0.27.0-SNAPSHOT / Java 21 baseline.

Reviewed changes

Copilot reviewed 72 out of 388 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
jooby/src/main/java/org/jooby/internal/BuiltinParser.java Introduces built-in parsing for primitives/collections/optional/enums/byte[]
jooby/src/main/java/org/jooby/internal/BodyReferenceImpl.java Adds body buffering-to-memory vs spool-to-file implementation
jooby/src/main/java/org/jooby/internal/AssetSource.java Adds filesystem/classpath asset resource abstraction
jooby/src/main/java/org/jooby/internal/AppPrinter.java Adds route + config tree printer for startup diagnostics
jooby/src/main/java/org/jooby/internal/AbstractRendererContext.java Adds shared renderer context send helpers and committed handling
jooby/src/main/java/org/jooby/handlers/SSIHandler.java Adds SSI asset handler that resolves include directives
jooby/src/main/java/org/jooby/handlers/CsrfHandler.java Adds CSRF token generation + verification filter
jooby/src/main/java/org/jooby/handlers/CorsHandler.java Adds CORS preflight/simple-request handling filter
jooby/src/main/java/org/jooby/handlers/Cors.java Adds configurable CORS policy model (origins/methods/headers/etc.)
jooby/src/main/java/org/jooby/handlers/AssetHandler.java Adds static assets handler w/ etag, last-modified, CDN support
jooby/src/main/java/org/jooby/funzy/When.java Adds functional “switch/case” helper (funzy)
jooby/src/main/java/org/jooby/View.java Adds view result type and view engine interface
jooby/src/main/java/org/jooby/Upload.java Adds multipart upload abstraction
jooby/src/main/java/org/jooby/Results.java Adds Result builder utilities (redirect/json/xml/content negotiation entrypoints)
jooby/src/main/java/org/jooby/Result.java Adds core Result object, headers/status/type, and content negotiation impl
jooby/src/main/java/org/jooby/RequestLogger.java Adds NCSA request logging handler with latency/extended options
jooby/src/main/java/org/jooby/Renderer.java Adds renderer SPI + rendering context contract
jooby/src/main/java/org/jooby/Registry.java Adds Guice-backed registry access abstraction
jooby/src/main/java/org/jooby/Parser.java Adds parser SPI for params/body parsing support
jooby/src/main/java/org/jooby/Mutant.java Adds typed parameter/header/body coercion facade
jooby/src/main/java/org/jooby/LifeCycle.java Adds lifecycle hooks + PostConstruct/PreDestroy support
jooby/src/main/java/org/jooby/FlashScope.java Adds flash-scope module backed by cookies
jooby/src/main/java/org/jooby/Err.java Adds framework exception type, mapping, and default handler
jooby/src/main/java/org/jooby/Deferred.java Adds async/deferred response handling
jooby/src/main/java/org/jooby/Cookie.java Adds cookie model + url codec + HMAC signature support
jooby/src/main/java/org/jooby/AsyncMapper.java Adds mapping from Callable/CompletableFuture to Deferred
jooby/src/main/java/org/jooby/Asset.java Adds asset abstraction and weak etag generation
jooby/spotbugs-exclude.xml Adds curated SpotBugs exclusions for vendored Jooby patterns
jooby/pom.xml Adds new Maven module for killbill-jooby with Jetty 11/Jakarta deps and test setup
jooby/README.md Documents vendored Jooby baseline, merged modules, and build/test commands
jooby/CHANGES.md Tracks fork deltas from upstream Jooby/funzy and migration notes
jdbi/src/main/java/org/killbill/commons/jdbi/guice/DataSourceProvider.java Switches injection annotations to jakarta.inject
jdbi/src/main/java/org/killbill/commons/jdbi/guice/DBIProvider.java Switches injection annotations to jakarta.inject
jdbi/spotbugs-exclude.xml Adds SpotBugs exclusions for CT_CONSTRUCTOR_THROW under Java 21
jdbi/pom.xml Bumps parent version and replaces javax.inject with jakarta.inject-api
embeddeddb/postgresql/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
embeddeddb/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
embeddeddb/mysql/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
embeddeddb/h2/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
embeddeddb/common/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
config-magic/src/main/java/org/skife/config/TimeSpan.java Makes TimeSpan final (immutability/intent)
config-magic/src/main/java/org/skife/config/DataAmount.java Makes DataAmount final (immutability/intent)
config-magic/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
concurrent/src/test/java/org/killbill/commons/concurrent/TestExecutors.java Adjusts thread-name assertions for Java 21 Thread.toString() formatting
concurrent/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
clock/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
automaton/src/main/java/org/killbill/automaton/StateMachineValidatingConfig.java Migrates JAXB to jakarta.xml.bind
automaton/src/main/java/org/killbill/automaton/DefaultTransition.java Migrates JAXB to jakarta.xml.bind
automaton/src/main/java/org/killbill/automaton/DefaultStateMachineConfig.java Migrates JAXB to jakarta.xml.bind
automaton/src/main/java/org/killbill/automaton/DefaultStateMachine.java Migrates JAXB to jakarta.xml.bind
automaton/src/main/java/org/killbill/automaton/DefaultState.java Migrates JAXB to jakarta.xml.bind
automaton/src/main/java/org/killbill/automaton/DefaultOperation.java Migrates JAXB to jakarta.xml.bind
automaton/src/main/java/org/killbill/automaton/DefaultLinkStateMachine.java Migrates JAXB to jakarta.xml.bind
automaton/pom.xml Bumps parent version to 0.27.0-SNAPSHOT
.github/workflows/sync.yml Switches shared workflow ref to java21
.github/workflows/snapshot.yml Switches shared workflow ref to java21
.github/workflows/release.yml Updates actions + Java setup to Temurin 21
.github/workflows/codeql-analysis.yml Switches shared workflow ref to java21
.github/workflows/cloudsmith_release.yml Switches shared workflow ref to java21
.github/workflows/ci.yml Switches shared workflow ref to java21
.github/agents/jooby-porting-expert.agent.md Adds repository agent instructions for Jooby porting/review
Files not reviewed (1)
  • .idea/encodings.xml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread jooby/src/main/java/org/jooby/internal/BuiltinParser.java
Comment thread jooby/src/main/java/org/jooby/internal/AssetSource.java
Comment thread jooby/src/main/java/org/jooby/handlers/AssetHandler.java
Comment thread jooby/src/main/java/org/jooby/handlers/Cors.java
Comment thread jooby/src/main/java/org/jooby/handlers/CorsHandler.java
Comment thread jooby/src/main/java/org/jooby/funzy/When.java
Comment thread jooby/src/main/java/org/jooby/RequestLogger.java
Comment thread jooby/src/main/java/org/jooby/Results.java
Comment thread jooby/src/main/java/org/jooby/handlers/SSIHandler.java
Comment thread jdbi/spotbugs-exclude.xml
Comment thread .github/agents/jooby-porting-expert.agent.md Outdated
Move the repository to the in-repo JDK 21 baseline and carry the local build
compatibility overrides needed until killbill-oss-parent catches up.

- update brittle tests for JDK 21 runtime changes
- override extra-enforcer-rules and SpotBugs to Java-21-capable versions
- point reusable CI workflows at the java21 shared-workflow branch
- triage Java 21 SpotBugs findings in vendored config-magic, jdbi, and Jooby

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@xsalefter xsalefter merged commit 5de36fd into master Apr 13, 2026
4 of 5 checks passed
@xsalefter xsalefter deleted the java2x branch April 13, 2026 19:48
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.

3 participants