Migrating Spring Boot 2.x Applications to Spring Boot 3.x: A Hands-On Guide

Spring Boot 3.x brings many improvements but also some breaking changes, most notably the move to Jakarta EE 9 namespaces and the baseline Java 17 requirement. Migrating your existing Spring Boot 2.x app to 3.x requires careful preparation and testing.

This guide walks you through the critical steps and highlights common pitfalls, with code snippets to illustrate each point.


Step 1: Upgrade Java to 17+

Spring Boot 3.x requires Java 17 or higher. So the first step is to ensure your project builds with Java 17.

Update your build file (Maven example):

<properties>
    <java.version>17</java.version>
</properties>

Or for Gradle:

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

Why?

Java 17 is an LTS version and offers new language features plus performance and security improvements. Spring Boot 3.x leverages these enhancements extensively.


Step 2: Change javax.* imports to jakarta.*

The biggest breaking change is the package namespace shift due to Jakarta EE 9.

What to do:

  • Update your imports in Java source files from javax.persistence.*, javax.servlet.*, javax.validation.*, etc., to jakarta.persistence.*, jakarta.servlet.*, jakarta.validation.*, and so forth.
  • Update dependency versions that rely on javax namespaces to their jakarta equivalents (e.g., Hibernate ORM 6.x).

Example before:

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Customer {
    @Id
    private Long id;
    //...
}

After:

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class Customer {
    @Id
    private Long id;
    //...
}

Tip: Use your IDE’s find & replace or refactoring tools to speed this process.


Step 3: Upgrade Spring Boot Dependencies

Update your Spring Boot version in your build file to 3.x.

Maven:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0</version>
    <relativePath/>
</parent>

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-web:3.0.0'

Make sure to update other Spring dependencies (Spring Security, Spring Data, etc.) to compatible versions as well.


Step 4: Handle Deprecated and Removed Features

Review your application for APIs and features deprecated in Spring Boot 2.x or removed in 3.x.

For example:

  • spring-boot-starter-actuator endpoints have been streamlined—verify which endpoints you expose.
  • Some properties in application.properties may be renamed or removed—consult the migration guide.

Step 5: Rebuild and Test

Once dependencies and code are updated:

  • Rebuild the project with Java 17 and Spring Boot 3.
  • Run your unit and integration tests.
  • Pay special attention to areas involving JPA, Servlets, validation, and any third-party integrations that may rely on javax.*.

Optional Step 6: Enable Native Image Support (If Applicable)

If you want to leverage Spring Boot 3’s native image support:

  1. Add the Spring Native dependency:
implementation 'org.springframework.boot:spring-boot-starter-native'
  1. Build the native image:
./mvnw spring-boot:build-image

or

./gradlew bootBuildImage
  1. Test the native executable thoroughly as it behaves slightly differently.

Example: Migrating a Simple REST Controller

Before (Spring Boot 2.x):

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String sayHello(@NotBlank String name) {
        return "Hello, " + name;
    }
}

After (Spring Boot 3.x):

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.validation.constraints.NotBlank;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String sayHello(@NotBlank String name) {
        return "Hello, " + name;
    }
}

The only change is the javax.validation.constraints.NotBlank import changed to jakarta.validation.constraints.NotBlank.


Common Migration Pitfalls & Tips

  • Third-party libraries: Some dependencies may not yet support Jakarta namespaces—check compatibility or upgrade accordingly.
  • Application properties: Some configuration keys have changed. Review logs for warnings and consult the migration guide.
  • Testing frameworks: Ensure your testing dependencies are updated and compatible with Java 17 and Spring Boot 3.
  • Use your IDE: Tools like IntelliJ or Eclipse can help refactor import namespaces in bulk.

Summary

Migrating to Spring Boot 3.x is mostly straightforward but requires careful handling of the Jakarta namespace shift and upgrading your Java version to 17+. The migration unlocks new language features, improved performance, and native image support.

The process steps:

  1. Upgrade Java to 17+
  2. Update javax.* imports to jakarta.*
  3. Upgrade Spring Boot and dependencies
  4. Refactor deprecated/removed APIs
  5. Test thoroughly
  6. Optionally, explore native images

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *