Skip to content

Migrate to Spring Boot 4 / Spring Framework 7 (BDK 4.x) - #889

Open
thibauult wants to merge 11 commits into
mainfrom
next
Open

Migrate to Spring Boot 4 / Spring Framework 7 (BDK 4.x)#889
thibauult wants to merge 11 commits into
mainfrom
next

Conversation

@thibauult

Copy link
Copy Markdown
Member

Why

BDK 3.x is built on Spring Boot 3.5, whose OSS support window has closed. Spring Boot 4 / Spring Framework 7 is the supported line, and this is the framework half of the BDK 4.x major — deliberately staying on Java 17 so the JDK bump (adopt-java-25-baseline) can follow against a build already known to be green on Spring Boot 4, rather than debugging two unrelated failure classes at once.

What changes

  • symphony-bdk-bom — spring-boot-dependencies 3.5.16 → 4.x. Drops the now-superseded Netty/Tomcat CVE overrides (Spring Boot 4 ships Netty 4.2 / Tomcat 11) and the hard-pinned Jakarta EE 10 API versions (jakarta.ws.rs-api, jakarta.validation-api), which Jakarta EE 11 now owns.
  • Starter autoconfiguration retargeting — @ConditionalOn* imports, AutoConfiguration.imports, health SPI move to spring-boot-health (AbstractHealthIndicator/Health/Status), HttpHeaders.asHttpHeaders() → headerSet(), SpyBean → MockitoSpyBean.
  • New starter smoke tests — boot a real @SpringBootApplication through each published starter (core, app, test-spring-boot) so autoconfiguration repackaging is caught by discovery, not by hand-assembled contexts. Written and passing against 3.5 first, to prove they'd have caught the Boot 4 breakage.
  • symphony-bdk-http-jersey2 → Apache HttpClient 5, following Jersey 4.0's connector move (org.apache.http.* → org.apache.hc.*).
  • Jackson 2 → Jackson 3 — 22 hand-written usages plus 5 test-side counterparts move to tools.jackson.*; jjwt-jackson replaced with a hand-rolled jjwt Serializer so only one Jackson databind implementation resolves on the classpath, enforced by a new verifySingleJacksonDatabind Gradle task. Breaking: BdkConfigParser's 3 public JsonNode-returning signatures change package.
  • Module rename: symphony-bdk-http-jersey2 → symphony-bdk-http-jersey (has been on Jersey 3.x for a while; a major is the only place an artifactId can change).
  • JSR-305 → JSpecify — 82 javax.annotation.Nonnull/Nullable usages across all modules, since Spring Framework 7 standardizes on JSpecify and JSR-305 is unmaintained with split-package issues.
  • Examples & verification — updated bdk-spring-boot-example/bdk-app-spring-boot-example to build against the new starters, plus additional JwtHelperTest coverage.
  • Docs — new docs/migration-4.x.md migration guide, versioned docs site config so 3.x docs stay reachable, README updates.

Breaking changes (expected in a major):

  • symphony-bdk-http-jersey2 artifactId no longer published (renamed)
  • BdkConfigParser's 3 JsonNode signatures change package (Jackson 3)
  • Nullability annotations move package (source-compatible, but visible to static analysis tooling)
  • Spring Boot 3 + BDK 4 is explicitly unsupported — consumers must be on Spring Boot 4

Also in this branch

  • Adds the /opsx:sync command/skill and mirrors all opsx commands/skills for the Gemini CLI (unrelated tooling change, not part of the Spring Boot 4 migration).

Test plan

  • ./gradlew build jacocoTestReport jacocoTestCoverageVerification
  • New starter smoke tests pass against Spring Boot 4 (already verified against 3.5 pre-bump)
  • verifySingleJacksonDatabind passes (no duplicate Jackson databind on classpath)
  • Examples (bdk-spring-boot-example, bdk-app-spring-boot-example) build and boot

Confirms Jersey 4.0.x pins Jackson 3 provider support and jackson-annotations
3.x retains the com.fasterxml.jackson.annotation package, so D2 adopts
Jackson 3 rather than shipping 4.0 on Jackson 2.
Boots a real @SpringBootApplication through each published starter
(core, app, and the test-spring-boot re-export) so autoconfiguration
repackaging in Spring Boot 4 is caught by discovery rather than by
tests that assemble a context by hand via AutoConfigurations. Written
and passing against 3.5.16 first, before the platform bump, so they
can demonstrate they would have caught the failure (D5).
Moves spring-boot-dependencies to 4.0.0 and realigns the jersey-bom
import to the Jersey line it pins. Drops the Netty and Tomcat CVE
overrides (D3) since Spring Boot 4 brings Netty 4.2 / Tomcat 11, both
of which already win conflict resolution against the old constraints,
and their comments cite CVEs specific to the Tomcat 10 line. Also
drops the jakarta.ws.rs-api and jakarta.validation-api pins, including
the duplicate validation-api pin in the app starter, early enough
that any Jakarta EE 11 incompatibility surfaces now rather than after
the rest of the migration is done.
@ConditionalOnMissingBean/@ConditionalOnProperty/@ConditionalOnBean and
the AutoConfiguration.imports path are unchanged in Spring Boot 4, so
the core and app starters' autoconfiguration classes need no import
changes; the section 2 smoke tests are what confirm discovery still
works. What does move: health SPI relocates to the new spring-boot-health
module (AbstractHealthIndicator/Health/Status -> ...boot.health.contributor),
HttpHeaders.asHttpHeaders() exposes headerSet() instead of entrySet() in
Spring Framework 7, and org.springframework.boot.test.mock.mockito.SpyBean
is removed in favour of MockitoSpyBean.
Jersey 4.0's Apache connector moved from jersey-apache-connector
(HttpClient 4, org.apache.http.*) to jersey-apache5-connector
(HttpClient 5, org.apache.hc.*): ApacheConnectorProvider /
ApacheClientProperties and the Registry-based SSL socket factory setup
are replaced by their Apache5 equivalents, and ApiClientJersey2's
NoHttpResponseException / ConnectTimeoutException imports move to
org.apache.hc.core5 / org.apache.hc.client5. jakarta.ws.rs itself is
untouched by this move. The jakarta.validation and jakarta.servlet.http
usages, and jakarta.annotation.PostConstruct, needed no changes under
Jakarta EE 11.
Adopts Jackson 3 per D2: a Jackson 3 JSON provider exists for the
Jersey 4.0.x line Spring Boot 4 pins
(tools.jackson.jakarta:jackson-jakarta-rs-json-provider), so the BOM
moves from jackson-bom 2.18.8 to tools.jackson:jackson-bom, and the 22
hand-written com.fasterxml.jackson.databind/.core usages across
symphony-bdk-config, symphony-bdk-core, symphony-bdk-http-jersey2, the
Spring starters, and symphony-bdk-cli move to tools.jackson.*, along
with their 5 test-side counterparts. jjwt-jackson is dropped in favour
of a hand-rolled jjwt Serializer backed by the shared mapper, so only
one Jackson databind implementation ever resolves on the classpath —
enforced by a new verifySingleJacksonDatabind Gradle task wired into
check. jackson-databind-nullable moves to 0.2.11 for its Jackson 3
backend, and JSON.java / RFC3339DateFormat.java are rewritten against
the Jackson 3 JsonMapper builder API and java.time respectively, since
Jackson 3 drops ISO8601DateFormat/ISO8601Utils. BdkConfigParser's 3
public JsonNode-returning signatures change package as a result — a
breaking API change for direct callers, to be called out in the
migration guide.
Adds the multi-store-aware /opsx:sync command and skill, updates the
existing apply/archive/explore/propose commands and skills for store
selection, and mirrors all opsx commands/skills for the Gemini CLI.
@thibauult thibauult changed the title Migrate to Spring Boot 4 / Spring Framework 7 (BDK 4.x) Migrate to Spring Boot 4 / Spring Framework 7 (BDK 4.x) Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

SNAPSHOT published: PR-889-SNAPSHOT
Repository: https://central.sonatype.com/repository/maven-snapshots/

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.

1 participant