Springboot 3 Upgrade

spring-boot 2.x.x to 3.1.2 migration

Right now I have to do a couple of spring-boot 2.5.x and 2.7.x upgrades to spring-boot 3.1.2 (current latest).
As this is a major version it is not necessarily trivial. Luckily a few very good hot-to’s have already been written,
so I will only mention the standard things, but I will also try to write about the other things I encountered during the
upgrade and about how I made it work.

Standard things to do

  • Install and use Java 17+ and make sure the project is using it. In the pom.xml:
1
2
3
4
5
6

<properties>
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
  • Upgrade to the latest version of spring-boot 2 (for me that is 2.7.14) and see if everything still works
  • Add the following dependency to the pom and build and run the application. In the run output you can find if
    properties have been changed and solve the problems
1
2
3
4
5
6
7

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<!-- <version>3.0.3</version>-->
<scope>runtime</scope>
</dependency>

If you have / use …

In this section I will describe the things I encountered during the upgrade and how I solved them.
If a title does not apply to you, just skip it.

your own starter modules

If you have your own starter(s) then it is important to upgrade them first.
And it is small but important change!

The META-INF/spring.factories file has changed
to META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports and the contents is only the fully
qualified AutoConfiguration class name or a list of them one per line

Before in spring.factories:

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration

Now in spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:

1
com.example.MyAutoConfiguration

Here is another example of
a META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
file from the spring-boot project itself.

org.openapitools:openapi-generator-maven-plugin

Add the useJakartaEe property as we start using the jakarta package instead of javax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.6.0</version>
<executions>
<execution>
<id>generate-server</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>openapi.yaml</inputSpec>
<generatorName>spring</generatorName>
[...]
<configOptions>
[...]
<useJakartaEe>true</useJakartaEe>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>

org.apache.maven.pluginsorg.apache.maven.plugins:maven-compiler-plugin

if you see this log message ding build:

1
[WARNING]  Parameter 'optimize' (user property 'maven.compiler.optimize') is deprecated: This property is a no-op in {@code javac}.
  • remove <optimize>true</optimize> option from the maven-compiler-plugin in the pom.xml

Spring security

and have tests defined using spring security make sure you have this dependency.

1
2
3
4
5
6

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

Prometheus

Key has changed from

1
2
3
metrics:
export:
prometheus:

to

1
2
3
4
5
management:
prometheus:
metrics:
export:
enabled: true

org.springframework.vault:spring-vault-core

In order to make this work I needed to add this dependency to my pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
<version>2.18.24</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>

plugins

If you have plugins in your pom.xml that were not compatible with java 17+ you might have this line in your
configuration:

1
--add-opens=java.base/java.lang=ALL-UNNAMED

It is no longer needed and can / should be removed.

PostgreSql’s JSONB data type

After upgrading you may see aan error on an annotation like this:

1
@Type(type = "jsonb")

It is no longer supported but can be changed by updating the dependency to:

1
2
3
4
5
6

<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-60</artifactId>
<version>2.21.1</version>
</dependency>

and change @Type(type = "jsonb") code lines to:

1
@Type(com.vladmihalcea.hibernate.type.json.JsonType.class)

and remove this line at the top of the class, as it is not needed anymore:

1
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)

BinderAwareChannelResolver not found

The BinderAwareChannelResolver class has been deprecated and removed. It is replaced by the org.springframework.cloud.stream.function.StreamBridge class.

Change the call to the BinderAwareChannelResolver to a call to the StreamBridge class.

BinderAwareChannelResolver to StreamBridge

In the new versions (dependencies) of spring-boot the BinderAwareChannelResolver has been removed. It is replaced by the StreamBridge class.

change the following code in the class using BinderAwareChannelResolver:

from:

1
2
3
4
5
6
7
8
9
import org.springframework.cloud.stream.binding.BinderAwareChannelResolver;
//[...]
private final BinderAwareChannelResolver channelResolver;
//[...]
private void sendMessageBatch(final Message<List<byte[]>> messageBatch) {
this.channelResolver
.resolveDestination("yourEventChannel")
.send(messageBatch);
}

to :

1
2
3
4
5
6
7
import org.springframework.cloud.stream.function.StreamBridge;
//[...]
private final StreamBridge streamBridge;
//[...]
private void sendMessageBatch(final Message<List<byte[]>> messageBatch) {
this.streamBridge.send("yourEventChannel", messageBatch);
}

openfeign client

if you have HTTP PATCH methods it will probably result in an error like this:

1
2
3
4
5
feign.RetryableException: Invalid HTTP method: PATCH executing PATCH [...]
at feign.FeignException.errorExecuting(FeignException.java:277) ~[feign-core-12.4.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:110) ~[feign-core-12.4.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:70) ~[feign-core-12.4.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:96) ~[feign-core-12.4.jar:na]

Add the following to your pom.xml or its equivalent in your build framework:

1
2
3
4
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>

change this property in the application.yaml or its equivalent in the application.properties:

from:

1
2
feign:
#feign properties here

to something like:

1
2
3
4
5
6
7
spring:
cloud:
openfeign:
okhttp:
# this will enable PATCH
enabled: true
# other properties here

Work in progress…
probably more to follow

References