Skip to content

Commit e652e16

Browse files
committed
Upgrade to Spring Boot 4.0
1 parent fba6706 commit e652e16

File tree

15 files changed

+82
-88
lines changed

15 files changed

+82
-88
lines changed

README.adoc

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
:RestTemplate: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html
1+
:RestClient: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html
22
:toc:
33
:icons: font
44
:source-highlighter: prettify
@@ -21,14 +21,14 @@ include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/
2121
[[scratch]]
2222
== Starting with Spring Initializr
2323

24-
You can use this https://start.spring.io/#!type=maven-project&groupId=com.example&artifactId=consuming-rest&name=consuming-rest&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.consuming-rest&dependencies=web[pre-initialized project] and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.
24+
You can use this https://start.spring.io/#!type=gradle-project&language=java&packaging=jar&groupId=com.example&artifactId=consuming-rest&name=consuming-rest&packageName=com.example.consuming-rest&dependencies=spring-restclient[pre-initialized project] and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.
2525

2626
To manually initialize the project:
2727

2828
. Navigate to https://start.spring.io.
2929
This service pulls in all the dependencies you need for an application and does most of the setup for you.
3030
. Choose either Gradle or Maven and the language you want to use.
31-
. Click *Dependencies* and select *Spring Web*.
31+
. Click *Dependencies* and select *HTTP Client*.
3232
. Click *Generate*.
3333
. Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.
3434

@@ -69,8 +69,8 @@ that looks something like this:
6969
That is easy enough but not terribly useful when fetched through a browser or through curl.
7070

7171
A more useful way to consume a REST web service is programmatically. To help you with that
72-
task, Spring provides a convenient template class called {RestTemplate}[`RestTemplate`].
73-
`RestTemplate` makes interacting with most RESTful services a one-line incantation. And it
72+
task, Spring provides a convenient template class called {RestClient}[`RestClient`].
73+
`RestClient` makes interacting with most RESTful services a one-line incantation. And it
7474
can even bind that data to custom domain types.
7575

7676
First, you need to create a domain class, a Java record class or Kotlin data class, to contain the data that you need.
@@ -135,10 +135,8 @@ Now you need to add a few other things to the `ConsumingRestApplication` class t
135135
show quotations from our RESTful source. You need to add:
136136

137137
* A logger, to send output to the log (the console, in this example).
138-
* A `RestTemplate`, which uses the Jackson JSON processing library to process the incoming
139-
data.
140-
* A `CommandLineRunner` that runs the `RestTemplate` (and, consequently, fetches our
141-
quotation) on startup.
138+
* A `CommandLineRunner` that builds a `RestClient` instance with the auto-configured `RestClient.Builder`
139+
and uses it to fetch our quotation on startup.
142140

143141
The following listing shows the finished `ConsumingRestApplication` class:
144142

@@ -155,14 +153,6 @@ include::complete-kotlin/src/main/kotlin/com/example/consumingrest/ConsumingRest
155153
----
156154
====
157155

158-
Finally, you need to set the server port. The quoters application uses the default
159-
server port, 8080, so this application cannot also use the same port. You can set
160-
the server port to 8081 by adding the following line to application properties
161-
(which the Initializr created for you):
162-
163-
----
164-
server.port=8081
165-
----
166156

167157
== Running the Application
168158

complete-kotlin/build.gradle.kts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
11
plugins {
2-
kotlin("jvm") version "1.9.25"
3-
kotlin("plugin.spring") version "1.9.25"
4-
id("org.springframework.boot") version "3.5.6"
2+
kotlin("jvm") version "2.2.21"
3+
kotlin("plugin.spring") version "2.2.21"
4+
id("org.springframework.boot") version "4.0.0"
55
id("io.spring.dependency-management") version "1.1.7"
66
}
77

88
group = "com.example"
99
version = "0.0.1-SNAPSHOT"
10-
java.sourceCompatibility = JavaVersion.VERSION_17
10+
11+
java {
12+
toolchain {
13+
languageVersion = JavaLanguageVersion.of(17)
14+
}
15+
}
1116

1217
repositories {
1318
mavenCentral()
1419
}
1520

1621
dependencies {
17-
implementation("org.springframework.boot:spring-boot-starter-web")
18-
testImplementation("org.springframework.boot:spring-boot-starter-test")
22+
implementation("org.springframework.boot:spring-boot-starter-restclient")
23+
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
24+
implementation("org.jetbrains.kotlin:kotlin-reflect")
25+
testImplementation("org.springframework.boot:spring-boot-starter-restclient-test")
26+
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
27+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
1928
}
2029

2130
kotlin {
22-
jvmToolchain(17)
2331
compilerOptions {
24-
freeCompilerArgs.addAll("-Xjsr305=strict")
32+
freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property")
2533
}
2634
}
2735

complete-kotlin/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

complete-kotlin/src/main/kotlin/com/example/consumingrest/ConsumingRestApplication.kt

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
package com.example.consumingrest
22

33
import org.slf4j.LoggerFactory
4-
import org.springframework.boot.CommandLineRunner
4+
import org.springframework.boot.ApplicationRunner
55
import org.springframework.boot.autoconfigure.SpringBootApplication
66
import org.springframework.boot.runApplication
7-
import org.springframework.boot.web.client.RestTemplateBuilder
87
import org.springframework.context.annotation.Bean
98
import org.springframework.context.annotation.Profile
10-
import org.springframework.web.client.RestTemplate
11-
import org.springframework.web.client.getForObject
9+
import org.springframework.web.client.RestClient
10+
import org.springframework.web.client.toEntity
1211

1312
private val log = LoggerFactory.getLogger(ConsumingRestApplication::class.java)
1413

1514
@SpringBootApplication
1615
class ConsumingRestApplication {
1716

18-
@Bean
19-
fun restTemplate(builder: RestTemplateBuilder): RestTemplate {
20-
return builder.build()
21-
}
22-
2317
@Bean
2418
@Profile("!test")
25-
fun run(restTemplate: RestTemplate) = CommandLineRunner {
26-
val quote = restTemplate.getForObject<Quote>("http://localhost:8080/api/random")
19+
fun run(builder: RestClient.Builder) = ApplicationRunner {
20+
val quote = builder.build().get().uri("http://localhost:8080/api/random")
21+
.retrieve().toEntity<Quote>()
2722
log.info(quote.toString())
2823
}
2924
}

complete-kotlin/src/test/kotlin/com/example/consumingrest/ConsumingRestApplicationTests.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,15 @@
1616

1717
package com.example.consumingrest
1818

19-
import org.assertj.core.api.Assertions.assertThat
2019
import org.junit.jupiter.api.Test
21-
import org.springframework.beans.factory.annotation.Autowired
2220
import org.springframework.boot.test.context.SpringBootTest
2321
import org.springframework.test.context.ActiveProfiles
24-
import org.springframework.web.client.RestTemplate
2522

2623
@SpringBootTest
2724
@ActiveProfiles("test")
2825
class ConsumingRestApplicationTest {
2926

30-
@Autowired
31-
private lateinit var restTemplate: RestTemplate
32-
3327
@Test
3428
fun contextLoads() {
35-
assertThat(restTemplate).isNotNull
3629
}
3730
}

complete/build.gradle

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
plugins {
2-
id 'org.springframework.boot' version '3.5.6'
2+
id 'org.springframework.boot' version '4.0.0'
33
id 'io.spring.dependency-management' version '1.1.7'
44
id 'java'
55
}
66

77
group = 'com.example'
88
version = '0.0.1-SNAPSHOT'
9-
sourceCompatibility = '17'
9+
10+
java {
11+
toolchain {
12+
languageVersion = JavaLanguageVersion.of(17)
13+
}
14+
}
1015

1116
repositories {
1217
mavenCentral()
1318
}
1419

1520
dependencies {
16-
implementation 'org.springframework.boot:spring-boot-starter-web'
17-
testImplementation 'org.springframework.boot:spring-boot-starter-test'
21+
implementation 'org.springframework.boot:spring-boot-starter-restclient'
22+
testImplementation 'org.springframework.boot:spring-boot-starter-restclient-test'
1823
}
1924

2025
test {

complete/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

complete/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>3.5.6</version>
8+
<version>4.0.0</version>
99
<relativePath/> <!-- lookup parent from repository -->
1010
</parent>
1111
<groupId>com.example</groupId>
@@ -21,12 +21,12 @@
2121
<dependencies>
2222
<dependency>
2323
<groupId>org.springframework.boot</groupId>
24-
<artifactId>spring-boot-starter-web</artifactId>
24+
<artifactId>spring-boot-starter-restclient</artifactId>
2525
</dependency>
2626

2727
<dependency>
2828
<groupId>org.springframework.boot</groupId>
29-
<artifactId>spring-boot-starter-test</artifactId>
29+
<artifactId>spring-boot-starter-restclient-test</artifactId>
3030
<scope>test</scope>
3131
</dependency>
3232
</dependencies>

complete/src/main/java/com/example/consumingrest/ConsumingRestApplication.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
5-
import org.springframework.boot.CommandLineRunner;
5+
6+
import org.springframework.boot.ApplicationRunner;
67
import org.springframework.boot.SpringApplication;
78
import org.springframework.boot.autoconfigure.SpringBootApplication;
8-
import org.springframework.boot.web.client.RestTemplateBuilder;
99
import org.springframework.context.annotation.Bean;
1010
import org.springframework.context.annotation.Profile;
11-
import org.springframework.web.client.RestTemplate;
11+
import org.springframework.web.client.RestClient;
1212

1313
@SpringBootApplication
1414
public class ConsumingRestApplication {
@@ -19,17 +19,15 @@ public static void main(String[] args) {
1919
SpringApplication.run(ConsumingRestApplication.class, args);
2020
}
2121

22-
@Bean
23-
public RestTemplate restTemplate(RestTemplateBuilder builder) {
24-
return builder.build();
25-
}
26-
2722
@Bean
2823
@Profile("!test")
29-
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
24+
public ApplicationRunner run(RestClient.Builder builder) {
25+
RestClient restClient = builder.baseUrl("http://localhost:8080").build();
3026
return args -> {
31-
Quote quote = restTemplate.getForObject(
32-
"http://localhost:8080/api/random", Quote.class);
27+
Quote quote = restClient
28+
.get().uri("/api/random")
29+
.retrieve()
30+
.body(Quote.class);
3331
log.info(quote.toString());
3432
};
3533
}

complete/src/test/java/com/example/consumingrest/ConsumingRestApplicationTest.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,17 @@
1616

1717
package com.example.consumingrest;
1818

19-
import static org.assertj.core.api.Assertions.assertThat;
20-
2119
import org.junit.jupiter.api.Test;
2220

23-
import org.springframework.beans.factory.annotation.Autowired;
2421
import org.springframework.boot.test.context.SpringBootTest;
2522
import org.springframework.test.context.ActiveProfiles;
26-
import org.springframework.web.client.RestTemplate;
2723

2824
@SpringBootTest
2925
@ActiveProfiles("test")
3026
public class ConsumingRestApplicationTest {
3127

32-
@Autowired
33-
private RestTemplate restTemplate;
34-
3528
@Test
3629
public void contextLoads() {
37-
assertThat(restTemplate).isNotNull();
3830
}
3931

4032
}

0 commit comments

Comments
 (0)