Friday, March 20, 2026

🚀 Spring Boot 3.5 → 4.0.3 Migration Summary

Import Changes, API Adjustments & Compatibility Results

A complete, real-world migration summary from Spring Boot 3.5 → 4.0, including breaking changes, dependency updates, and fixes across Web, JPA, Jackson 3, GCP, Pub/Sub, Thymeleaf, and Testing.

  

🔁 Key Import & API Changes


1️⃣ RestTemplate Builder (Client API)

❌ Removed

org.springframework.boot.web.client.RestTemplateBuilder

✅ Replaced With

org.springframework.boot.restclient.RestTemplateBuilder

✅ Dependency Change

Spring Boot 3

spring-boot-starter-web

Spring Boot 4

spring-boot-starter-webmvc
spring-boot-starter-restclient

📌 Reason Spring Boot 4 separates responsibilities:

  • Server → spring-boot-starter-webmvc
  • Client → spring-boot-starter-restclient


2️⃣ EntityManager Factory Builder

❌ Removed

org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder

✅ Replaced With

org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean

📌 Reason Spring Boot 4 removes Boot-specific abstractions → use standard Spring Framework APIs.


3️⃣ Jackson Migration (🔥 Major Change)

❌ Removed (Explicit Jackson 2)

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

✅ Added (Boot 4 Default – Jackson 3)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
</dependency>

<dependency>
    <groupId>tools.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

✅ Boot 4 Now Uses

import tools.jackson.core.json.JsonReadFeature;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.JsonNode;

⚠️ Compatibility Note

Libraries such as springdoc still use Jackson 2 internally → ✔️ Fully compatible (can run in parallel)


🔧 ObjectMapper Migration

Spring Boot 3

this.objectMapper
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

Spring Boot 4 (Rebuild from existing)

this.objectMapper =
    ((JsonMapper) objectMapper)
        .rebuild()
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        .configure(JsonReadFeature.ALLOW_SINGLE_QUOTES, true)
        .build();

Alternative (New Instance)

this.objectMapper =
    JsonMapper.builder()
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        .configure(JsonReadFeature.ALLOW_SINGLE_QUOTES, true)
        .build();

📌 Jackson 3 Package Changes

 Article content

 

👉 Important: Annotations (@JsonProperty, etc.) remain unchanged → ✔️ No changes required in model/POJO classes


🔍 Migration Tip

grep -r "com.fasterxml.jackson.databind.ObjectMapper" src/main/java

4️⃣ HTTP Exception Constructor Change

❌ Old

new HttpMessageNotReadableException(message, cause);

✅ New

new HttpMessageNotReadableException(message, (HttpInputMessage) null);

📌 Reason Spring Framework 7 removed the Throwable constructor.


5️⃣ ResponseEntity Test Constructor Fix

❌ Broken in Boot 4

new ResponseEntity<>(null, HttpStatus.OK);

✅ Fixed

ResponseEntity.ok(null);

or

new ResponseEntity<String>((String) null, HttpStatus.OK);

6️⃣ Test Stack Migration

❌ Removed

spring-boot-starter-test

✅ Replaced With

spring-boot-starter-webmvc-test

✅ New Test Platform Versions

  • JUnit 6
  • Mockito 5
  • AssertJ 3.27
  • Awaitility 4.3


7️⃣ Lombok (⚠️ Build-Time Configuration Required)

✅ Dependency

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

✅ Maven Compiler Plugin Setup

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>${java.version}</source>
        <target>${java.version}</target>
        <annotationProcessorPaths>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

✅ Spring Boot Plugin Exclusion

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <excludes>
            <exclude>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </exclude>
        </excludes>
    </configuration>
</plugin>

📌 Reason Lombok must run only at compile-time → not packaged into runtime artifact.


8️⃣ Google Cloud (Secret Manager + Storage)

✅ Dependencies

<!-- Google Cloud Dependencies -->
<dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-secretmanager</artifactId>
</dependency>

⚠️ Jackson Conflict Fix

Exclude Jackson 2 XML module:

<dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>google-cloud-storage</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
        </exclusion>
    </exclusions>
</dependency>

✅ Dependency Management (BOM)

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>spring-cloud-gcp-dependencies</artifactId>
            <version>8.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

9️⃣ Pub/Sub / Spring Integration

❌ Spring Boot 3

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-core</artifactId>
</dependency>

✅ Spring Boot 4

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-integration</artifactId>
</dependency>

📌 Notes

  • spring-boot-starter-integration auto-configures integration
  • @EnableIntegration becomes available
  • Required for Pub/Sub + Spring Integration flows


Pub/Sub Dependency

<dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
</dependency>

🔟 Testcontainers Migration

Spring Boot 3

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>oracle-free</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>gcloud</artifactId>
</dependency>

Spring Boot 4

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers-junit-jupiter</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers-oracle-free</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers-postgresql</artifactId>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers-gcloud</artifactId>
</dependency>

1️⃣1️⃣ Thymeleaf (⚠️ Known Issue in Boot 4)

Issue

org.thymeleaf:thymeleaf-spring6 → compatibility issue with Spring Framework 7

✅ Workaround (Manual Bean)

@Configuration
public class ThymeleafManualConfig {

    @Bean(name = "manualTemplateEngine")
    @Primary
    public TemplateEngine manualTemplateEngine() {
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        resolver.setPrefix("templates/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode(TemplateMode.HTML);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setCacheable(false);
        resolver.setCheckExistence(true);

        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(resolver);
        return engine;
    }
}

⚠️ Important

Avoid bean conflict:

templateEngine already exists → disable or rename

1️⃣2️⃣ Test (Jackson Mock Change)

Spring Boot 3

when(jsonMapperBuilder.enable(any(DeserializationFeature.class)))
    .thenReturn(jsonMapperBuilder);

when(jsonMapperBuilder.enable(any(JsonParser.Feature.class)))
    .thenReturn(jsonMapperBuilder);

Spring Boot 4

import tools.jackson.databind.json.JsonMapper;

@Mock
private JsonMapper objectMapper;

JsonMapper realMapper = JsonMapper.builder().build();

1️⃣3️⃣ Springdoc OpenAPI (⚠️ Jackson 2 Compatibility)

✅ Dependency (Spring Boot 4 Supported Version)

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>3.0.2</version>
</dependency>

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
    <version>3.0.2</version>
</dependency>

⚠️ Important Behavior

  • Spring Boot 4 → uses Jackson 3 (tools.jackson.*)
  • Springdoc (3.0.2) → still uses Jackson 2 (com.fasterxml.*) internally

✅ Final Conclusion

✔️ The full platform is fully functional on Spring Boot 4.0:

  • Web (Spring MVC)
  • JPA / Hibernate
  • Jackson 3
  • Pub/Sub + Spring Integration
  • GCP Secret Manager
  • Testcontainers
  • Lombok (compile-time only)
  • Observability / Actuator

👉 After applying all fixes → no runtime issues


💡 Final Insight

Spring Boot 4 is not just an upgrade — it’s a platform evolution:

  • Clear separation of responsibilities
  • Reduced framework magic
  • Stronger dependency control
  • Future-ready ecosystem (Java 21, Java 25 +, Framework 7)


🔗 References

Here are the official docs and community discussions used during the migration:

📘 Spring Boot & Framework


☁️ Google Cloud (GCP)


🔄 Jackson 3


🔌 Spring Integration


💬 Community Discussion


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 










No comments:

Post a Comment

🚀 Spring Boot 3.5 → 4.0.3 Migration Summary

Import Changes, API Adjustments & Compatibility Results A complete, real-world migration summary from Spring Boot 3.5 → 4.0, including b...