DEV Community

Cover image for Migrating to Spring Boot 3.0 and Java 17: A Comprehensive Guide
Guilherme Nichetti
Guilherme Nichetti

Posted on

Migrating to Spring Boot 3.0 and Java 17: A Comprehensive Guide

Spring Boot 3.0 marks a significant upgrade, introducing new features and enhancements. However, it mandates Java 17 as the minimum version and presents several compatibility challenges. This guide aims to help you navigate the migration process smoothly.

Benefits

Upgrading to Java 17

To use Spring Boot 3.0, you must upgrade to JDK 17. This upgrade allows you to leverage the latest features and performance improvements in Java 17.

Support for GraalVM Native Image

GraalVM Native Images offer a novel method to deploy and run Java applications, providing benefits such as instantaneous startup and reduced memory usage, which are significant pain points for Spring Boot applications.

Enhanced Observability with Micrometer and Micrometer Tracing

These tools offer improved observability features. More details can be found on the official documentation.

Drawbacks

Time and Resource Requirements

Migrating to a new major release demands substantial time and resources, especially for thorough testing. This process impacts all your application flows and requires comprehensive testing. While updating code might take a few days, testing can extend over a week or more, depending on your project's complexity.

Potential for New Bugs

Since the migration impacts all application flows, insufficient test coverage might lead to missed bugs. Ensure extensive end-to-end testing and scrutinize logs for any new exceptions or discrepancies compared to the previous state.


Preparation Steps

1. Upgrade to Spring Boot 2.7 First

If you're using an earlier version of Spring Boot, upgrade to Spring Boot 2.7 first to minimize compatibility issues during the migration to 3.0.

2. Review Dependencies

Examine your dependencies and dependency management for Spring Boot 3.x to assess their impact on your project. For dependencies not managed by Spring Boot, identify compatible versions before upgrading.

3. Address Deprecations

Classes, methods, and properties deprecated in Spring Boot 2.x have been removed in this release. Ensure your code does not call any deprecated methods before upgrading.


Migration Steps

1. Configuration Properties Migration

Add the following dependency to your Maven pom.xml to include the Spring Boot Properties Migrator:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode

This tool will analyze your application's environment and print diagnostics in the startup console logs, guiding you on how to update your properties accordingly.

2. Update Dependencies
Update your pom.xml with the new parent POM and Java version:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.5</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <java.version>17</java.version>
</properties>
Enter fullscreen mode Exit fullscreen mode

Avoid specifying versions for Spring Data JPA, Spring Web, Spring Data Redis, etc., as their compatible versions are declared in the parent POM.

If you are using any of these dependencies, update to the following versions to ensure compatibility:

MySQL Connector:

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.1.0</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Logback:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.4.11</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

OpenFeign:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>4.0.4</version>
</dependency>

Enter fullscreen mode Exit fullscreen mode

Spring JDBC:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>6.0.12</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Jackson Databind:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.3</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.15.3</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Redisson:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.24.3</version>
</dependency>
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-data-31</artifactId>
    <version>3.24.3</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Mockito:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.3.1</version>
    <scope>test</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode

JJWT:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.12.3</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Springdoc OpenAPI:

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

Enter fullscreen mode Exit fullscreen mode

Spring Kafka:

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
    <version>3.0.10</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

3. Rebuild and Modify Code

After updating dependencies, rebuild your code with mvn clean package. You'll encounter issues with javax imports, which need to be replaced with jakarta.

Hibernate Configuration

In Hibernate 6, use MySQLDialect for all MySQL versions. Update your application properties as follows:

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

4. Update Spring Security Configuration

If you're using WebSecurityConfigurerAdapter, you'll need to migrate to a lambda-based configuration.

Old Configuration:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  // Configuration code
}
Enter fullscreen mode Exit fullscreen mode

New Configuration:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig {
  @Bean
  public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
    return authConfig.getAuthenticationManager();
  }

  @Bean
  protected SecurityFilterChain configure(HttpSecurity http) throws Exception {
    http.cors(AbstractHttpConfigurer::disable).csrf(AbstractHttpConfigurer::disable);
    http.authorizeHttpRequests(auth -> auth.requestMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated());
    http.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
    http.exceptionHandling(ex -> ex.authenticationEntryPoint(authEntryPointJwt));
    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    return http.build();
  }
}
Enter fullscreen mode Exit fullscreen mode

JJWT Library Updates

Update your JJWT code to the new API format.

Old Code:

public String generateJwtToken(Long userId) {
  return Jwts.builder()
      .setSubject(userId.toString())
      .setIssuedAt(new Date())
      .setExpiration(new Date(new Date().getTime() + jwtExpirationMs))
      .signWith(SignatureAlgorithm.HS256, jwtSecret.getBytes(StandardCharsets.UTF_8))
      .compact();
}
Enter fullscreen mode Exit fullscreen mode

New Code:

public String generateJwtToken(Long userId) {
  return Jwts.builder()
      .subject(userId.toString())
      .issuedAt(new Date())
      .expiration(new Date(new Date().getTime() + jwtExpirationMs))
      .signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8)), Jwts.SIG.HS256)
      .compact();
}
Enter fullscreen mode Exit fullscreen mode

Final Steps

Rebuild your project and test thoroughly. Carefully verify all APIs for discrepancies or exceptions, monitoring logs throughout the process.

Conclusion

Migrating to Spring Boot 3.0 and JDK 17 is a complex but manageable process. It involves addressing several compatibility issues and updating numerous dependencies. Thorough testing is crucial to ensure a smooth transition.

The only way to make sense out of change is to plunge into it, move with it, and join the dance. - Alan Watts

Top comments (0)