Skip to content

Spring boot 4.1.0 migration#358

Merged
KarimGl merged 21 commits into
mainfrom
chore/spring4
Jul 15, 2026
Merged

Spring boot 4.1.0 migration#358
KarimGl merged 21 commits into
mainfrom
chore/spring4

Conversation

@KarimGl

@KarimGl KarimGl commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Issue Number

fixes #

Describe the changes you've made

Spring Boot 4 Migration

Motivation

Spring Boot 3 reached its end of support window.

This PR upgrades the full stack to Spring Boot 4.1.0 (starting from 4.0.6), which pulls in:

  • Spring Framework 7
  • Spring Security 7
  • Jackson 3 (tools.jackson)
  • Kotlin 2.4
  • Spring Kafka 4 (KRaft)
  • Tomcat 11 (replacing Undertow)
  • Updated testing and container tooling

Dependency Changes

Area Before After
Spring Boot BOM spring-boot-starter-parent spring-boot-dependencies
Jackson group com.fasterxml.jackson tools.jackson
Servlet container Undertow Tomcat
Embedded Kafka broker EmbeddedKafkaZKBroker (ZooKeeper) EmbeddedKafkaKraftBroker (KRaft)
AOP starter spring-boot-starter-aop spring-boot-starter-aspectj
Test starters spring-boot-starter-test (monolith) Fine-grained webmvc-test, jdbc-test, data-jpa-test, data-ldap-test
Testcontainers postgresql, junit-jupiter testcontainers-postgresql, testcontainers-junit-jupiter
Kotlin 1.x 2.4.0

Jackson 2 → Jackson 3

API Changes

  • All imports migrated from com.fasterxml.jackson.databind.* to tools.jackson.databind.*
  • new ObjectMapper()JsonMapper.builder()...build()
  • findAndRegisterModules()findAndAddModules()
  • setSerializationInclusion()changeDefaultPropertyInclusion()
  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPSDateTimeFeature.WRITE_DATES_AS_TIMESTAMPS
  • MappingJackson2HttpMessageConverterJacksonJsonHttpMessageConverter
  • JsonGenerator.Feature.AUTO_CLOSE_TARGETStreamWriteFeature.AUTO_CLOSE_TARGET
  • StdSerializer / JsonDeserializerValueDeserializer
  • SerializerProviderSerializationContext
  • gen.writeStringField()gen.writeStringProperty()
  • JsonProcessingException / IOException catch blocks → JacksonException
  • SPI file renamed: com.fasterxml.jackson.databind.Moduletools.jackson.databind.JacksonModule

Unchanged

Jackson 3 keeps annotation packages unchanged — @JsonProperty, @JsonCreator, @JsonIgnore, etc. remain under com.fasterxml.jackson.annotation.*.

Immutables Annotation Inheritance

Jackson 3 no longer inherits annotations through interfaces.

Affected DTOs include:

  • ExecutionSummaryDto
  • GwtTestCaseDto
  • TestCaseIndexDto
  • DataSetDto
  • ~15 additional DTOs

Fix applied:

  • Added @JsonCreator static factory methods directly on DTO interfaces.
  • Registered ImmutablesJacksonMixins in WebConfiguration and ServerConfiguration.
  • A new ImmutablesDtoSerializationTest validates round-trip serialization/deserialization for all affected DTOs.

Spring Security 7

Removed ChannelSecurityConfigurer

requiresChannel() is no longer available.

Replacement: TomcatHttpsRedirectConfig, activated via the https-redirect profile.

Package Changes

OAuth2ResourceServerProperties moved to org.springframework.boot.security.oauth2.server.resource.autoconfigure.

Autoconfiguration Exclusions

@SpringBootApplication(exclude = ...) became @SpringBootApplication(excludeName = ...) because several autoconfiguration classes moved packages.


Spring Boot 4 API Changes

Servlet Factory

AbstractServletWebServerFactoryConfigurableServletWebServerFactory

DataSourceProperties

Moved from org.springframework.boot.autoconfigure.jdbc to org.springframework.boot.jdbc.autoconfigure.

Prometheus

The Prometheus actuator endpoint is now exposed by default. Integration test updated: NOT_FOUNDOK.


Kafka: ZooKeeper → KRaft

Spring Kafka 4 removed EmbeddedKafkaZKBroker and replaced it with EmbeddedKafkaKraftBroker.

Impact: KRaft brokers use dynamic ports. KafkaBrokerStartAction now explicitly exposes bootstrapServers as an output so scenarios can wire broker addresses correctly.


Lucene and Logging

Lucene

OnDiskIndexConfig now treats CorruptIndexException and IndexFormatTooOldException as recoverable failures. The directory is properly closed before index recreation.

Logging

Replaced Undertow loggers (io.undertow, org.xnio) with Tomcat logger (org.apache.catalina).


Bug Fixes Identified During Migration

HTTP Connect Timeout Restored

Component: HttpClientFactory

During the Apache HttpClient 5 migration only socket read timeouts were preserved. Connect timeout was reintroduced:

RequestConfig.custom()
    .setConnectTimeout(Timeout.ofMilliseconds(timeout))

TCP connection attempts now fail correctly on timeout; all HTTP actions honor connection timeouts again.

Scheduling Campaign Backward Compatibility

Component: SchedulingCampaignsDtoDeserializer

Legacy Jackson 2 persisted LocalDateTime values as arrays:

[2020,2,4,7,10]

Without a fix, existing persisted files would fail to deserialize.

Solution: Use treeToValue(...) with a static mapper. Jackson 3's LocalDateTimeDeserializer now accepts both the legacy array format and ISO-8601 strings ("2020-02-04T07:10:00").

KafkaBrokerStopAction Failure Propagation

Previous behavior: broker.destroy() exceptions were swallowed and the action always returned ok().

New behavior: ko() is returned when broker shutdown fails.

HTTPS Enforcement Alignment

Component: NoAuthSecurityConfig

Previously NoAuthSecurityConfig still enforced requiresInsecure() while ChutneyWebSecurityConfig no longer did. This inconsistency has been removed. HTTPS redirection is now handled exclusively by TomcatHttpsRedirectConfig under the https-redirect profile.

String Controller Responses

Component: WebConfiguration

Jackson 3 JSON-encodes String return values ("1") instead of writing them as plain text (1), breaking integrations relying on Spring Boot 3 behavior (curl, Jenkins, scripts).

Fix:

  • Added application/json support to StringHttpMessageConverter.
  • Registered via extendMessageConverters(...).
  • A static plainTextStringConverter() helper is exposed on WebConfiguration for standalone MockMvc test setups that bypass the Spring context.

Bare-string endpoints preserve pre-migration output.

Removal of FAIL_ON_NULL_FOR_PRIMITIVES Override

Component: WebConfiguration

The migration initially retained FAIL_ON_NULL_FOR_PRIMITIVES = false, which silently converted {"count": null} into 0 or false. The override has been removed to restore strict validation semantics.

JiraTargetConfigurationDto Restoration

@JsonCreator moved from a no-arg constructor to an all-args constructor with explicit @JsonProperty annotations on parameters. Default behavior for missing proxy fields remains unchanged through Objects.requireNonNullElse(...).

Narrowed Exception Handling

Component: ScenarioExecutionReportEntity

catch (Exception e)catch (JacksonException e) to avoid masking unrelated runtime failures.


Non-Migration Change

Scenario Index API Enrichment

TestCaseIndexDto now includes author and version. These fields are exposed through the scenario index API and consumed by the Angular UI.


Post-Initial-Migration Bumps

Spring Boot 4.0.6 → 4.1.0

Upgraded after the initial migration settled to pick up Spring Boot 4.1.0 fixes and improvements.

Additional dependency updates in the same pass:

Dependency Before After
Immutables 2.11.6 2.12.2
Guava 33.5.0-jre 33.6.0-jre
Commons IO 2.21.0 2.22.0
Liquibase 5.0.2 5.0.3
jqwik 1.9.3 1.10.1

IntelliJ Plugin: Kotlin 2.4.0

The idea-plugin Gradle build was updated separately (it uses its own toolchain):

  • kotlin version in libs.versions.toml: 2.3.x → 2.4.0
  • Compiler language and API versions set to 2.4
  • JsonTraversal.kt adapted for Kotlin 2.4 API changes

Describe if there is any unusual behaviour of your code

Additional context

Test plan

Checklist

  • Refer to issue(s) the PR solves
  • New java code is covered by tests
  • Add screenshots or gifs of the new behavior, if applicable.
  • All new and existing tests pass
  • No git conflict

@KarimGl
KarimGl requested a review from joelgaspard June 24, 2026 06:10
@KarimGl
KarimGl marked this pull request as ready for review June 26, 2026 13:29
@KarimGl KarimGl changed the title Spring boot 4.0.6 migration Spring boot 4.1.0 migration Jul 1, 2026
private static String brokersAsString(EmbeddedKafkaBroker value) {
try {
return value.getBrokersAsString();
} catch (RuntimeException e) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is it needed to catch RuntimeException ? is IllegalArgumentException not enough ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

EmbeddedKafkaBroker.getBrokersAsString() throws a RuntimeException when the broker has been shut down (the Kafka broker is no longer
running), so catching it and returning "shut down" can be the correct defensive fallback for serialization purposes

broker.destroy();
return ActionExecutionResult.ok();
} catch (Exception e) {
logger.error("Kafka broker shutdown failed: " + e.getMessage());

@joelgaspard joelgaspard Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe we should log the stack trace.
Why should we throw this large scope : Exception ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

destroy() throws Exception in DisposableBean interface

@joelgaspard joelgaspard Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Well, I think there is EmbeddedKafkaBroker which overrides destroy() method without throwing Exception.
Not blocking for me

KarimGl added 21 commits July 9, 2026 16:22
- Bump springboot.version 3.5.11 → 4.0.6 (Spring Framework 7.x)
- Bump Kotlin 1.9.25 → 2.2.0 (required by SB4); update compiler/api version
- Bump testcontainers BOM 2.0.4 → 2.0.5

Undertow removal (dropped in SB4 / Servlet 6.1):
- Replace spring-boot-starter-undertow with spring-boot-starter-tomcat
- Rewrite UndertowConfig.java as TomcatServletWebServerFactory customizer
  preserving HTTP→HTTPS redirect on port 80→443 via SecurityConstraint
- Rename profile undertow-https-redirect → https-redirect in application.yml files

Starter renames (SB4 modular naming):
- spring-boot-starter-web → spring-boot-starter-webmvc
- spring-boot-starter-oauth2-resource-server → spring-boot-starter-security-oauth2-resource-server
- spring-security-test → spring-boot-starter-security-test
- Add spring-boot-properties-migrator (runtime, temporary)
- Remove <executable>true</executable> from spring-boot-maven-plugin (launch scripts dropped)

Jackson 3 (group ID change com.fasterxml.jackson → tools.jackson):
- Update all sub-module poms: server, jira, engine, tools, action-impl, kotlin-dsl
- Remove jackson-datatype-jdk8 (merged into Jackson 3 core)
- Update BrokerMQModule and BrokerServiceSerializer imports
- Update Scala module exclusion to tools.jackson.module group

WSS4J 1.6.19 → 3.0.4 (Jakarta EE 11 compatible):
- Change groupId org.apache.ws.security:wss4j → org.apache.wss4j:wss4j-ws-security-dom
- Bump Apache Santuario xmlsec 1.5.8 → 3.0.4 (required by WSS4J 3.x)
- Migrate SoapFunction.java to WSS4J 2.x/3.x API:
  WSSecHeader(doc) + insertSecurityHeader() + WSSecUsernameToken(secHeader) + build()

Application code cleanup:
- Remove unused HandlerMappingIntrospector local in ChutneyWebSecurityConfig
- Rename Hibernate javax.cache → jakarta.cache in application.yml (Hibernate 7)
- Fix DefaultPrettyPrinter: remove withSeparators override (fields are final in
  Jackson 3); use jacksonMapperBuilder() builder pattern for mapper initialization
- Fix JsonReportWriter: replace ObjectMapper().findAndRegisterModules() with
  jacksonMapperBuilder().disable(...).build()
- Fix JUnit Platform 6: make PostDiscoveryFilter.apply() parameter non-nullable
- Fix test files: replace MappingJackson2HttpMessageConverter with
  JacksonJsonHttpMessageConverter; fix findAndRegisterModules() usages
- Fix EmbeddedKafkaZKBroker: replaced by EmbeddedKafkaKraftBroker in Spring Kafka 4
- Fix TextNode: renamed to StringNode in Jackson 3
- Fix ObjectNode.elements(): renamed to values() in Jackson 3 (returns Collection)
- Fix HttpHeaders: no longer implements Map in Spring 7, use asMultiValueMap()
- Fix HttpEntity(null): disambiguate null constructor call with HttpEntity.EMPTY
- Update example module Kotlin version from 1.9.25 to 2.2.0
Jackson 3 with ImmutablesJacksonMixins now produces nested JSON:
{ "metadata": { "id", "title", ... } } — matching the UI expectation.

- Add TypeScript DTO interfaces (TestCaseIndexDto, ScenarioIndexMetadataDto,
  ExecutionSummaryDto) to lock the API contract in the frontend
- Fix scenario.service.ts: parse creationDate/updateDate as Date,
  use Execution.deserialize for executions, drop ghost version/author reads
- Fix campaign.service.ts: wrong constructor argument order (tags was
  landing in the updateDate slot, executions in the version slot);
  apply same DTO types and date parsing as scenario.service.ts
@KarimGl
KarimGl requested a review from joelgaspard July 9, 2026 15:08
@KarimGl
KarimGl merged commit 2202376 into main Jul 15, 2026
4 checks passed
@KarimGl
KarimGl deleted the chore/spring4 branch July 15, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants