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-webSpring 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
👉 Important: Annotations (@JsonProperty, etc.) remain unchanged → ✔️ No changes required in model/POJO classes
🔍 Migration Tip
grep -r "com.fasterxml.jackson.databind.ObjectMapper" src/main/java4️⃣ 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 rename1️⃣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
- Spring Boot 4.0 Migration Guide https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide
- Spring Framework 7 Reference https://docs.spring.io/spring-framework/reference/
☁️ Google Cloud (GCP)
- Spring Cloud GCP Repository https://github.com/GoogleCloudPlatform/spring-cloud-gcp
🔄 Jackson 3
- Jackson Project (GitHub) https://github.com/FasterXML/jackson
🔌 Spring Integration
- Spring Integration Reference https://docs.spring.io/spring-integration/reference/overview.html
- What’s New in Spring Integration https://docs.spring.io/spring-integration/reference/whats-new.html#whats-new-part
- Spring Integration 7 Release Blog https://spring.io/blog/2025/11/19/spring-integration-7-0-0-released
- Spring Boot Integration Docs https://docs.spring.io/spring-boot/reference/messaging/spring-integration.html
💬 Community Discussion
- Stack Overflow – Boot 4 + GCP Issue https://stackoverflow.com/questions/79838205/spring-boot-4-0-0-gcp-java-lang-nosuchmethoderror-org-springframework-boot
No comments:
Post a Comment