Skip to content

Commit 3fe8455

Browse files
authored
upgrade to Spring Boot 4.0 (#482)
1 parent 84c585c commit 3fe8455

24 files changed

Lines changed: 189 additions & 128 deletions

.github/workflows/local-development-verification.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Verify Local Development
22

33
on:
44
schedule:
5-
- cron: '0 5 * * *' # Runs everyday at 5 AM
5+
- cron: '0 5 * * *' # Runs every day at 5 AM
66
workflow_dispatch:
77
push:
88

.github/workflows/maven.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ jobs:
2727
cache-dependency-path: src/frontend/package-lock.json
2828

2929
- name: Build project
30-
timeout-minutes: 15
30+
id: build
3131
continue-on-error: true
3232
run: ./mvnw verify --no-transfer-progress
3333

3434
- name: Flatten Selenide Screenshots and HTML source code on failure
35-
if: ${{ failure() }}
35+
if: ${{ always() && steps.build.outcome == 'failure' }}
3636
working-directory: target
3737
env:
3838
SOURCE_FOLDER: selenide-screenshots
@@ -49,7 +49,11 @@ jobs:
4949
5050
- name: Archive Selenide outcome on failure
5151
uses: actions/upload-artifact@v4
52-
if: ${{ failure() }}
52+
if: ${{ always() && steps.build.outcome == 'failure' }}
5353
with:
5454
name: selenide-failure-captures
5555
path: target/aggregated-outcome
56+
57+
- name: Fail pipeline if build failed
58+
if: ${{ steps.build.outcome == 'failure' }}
59+
run: exit 1

pom.xml

Lines changed: 67 additions & 26 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.0</version>
8+
<version>4.0.2</version>
99
<relativePath/>
1010
<!-- lookup parent from repository -->
1111
</parent>
@@ -19,8 +19,8 @@
1919
<properties>
2020
<java.version>21</java.version>
2121
<node.version>v18.16.0</node.version>
22-
<spring-cloud-aws.version>3.4.0</spring-cloud-aws.version>
23-
<testcontainers.version>1.21.3</testcontainers.version>
22+
<spring-cloud-aws.version>4.0.0</spring-cloud-aws.version>
23+
<testcontainers.version>2.0.3</testcontainers.version>
2424
<wiremock.version>3.13.0</wiremock.version>
2525
<p6spy.version>3.9.1</p6spy.version>
2626
<mockito.version>5.11.0</mockito.version>
@@ -58,7 +58,11 @@
5858
<dependencies>
5959
<dependency>
6060
<groupId>org.springframework.boot</groupId>
61-
<artifactId>spring-boot-starter-web</artifactId>
61+
<artifactId>spring-boot-starter-webmvc</artifactId>
62+
</dependency>
63+
<dependency>
64+
<groupId>org.springframework.boot</groupId>
65+
<artifactId>spring-boot-starter-webclient</artifactId>
6266
</dependency>
6367
<dependency>
6468
<groupId>org.springframework.boot</groupId>
@@ -72,6 +76,10 @@
7276
<groupId>org.springframework.boot</groupId>
7377
<artifactId>spring-boot-starter-validation</artifactId>
7478
</dependency>
79+
<dependency>
80+
<groupId>org.springframework.boot</groupId>
81+
<artifactId>spring-boot-starter-restclient</artifactId>
82+
</dependency>
7583

7684
<dependency>
7785
<groupId>io.awspring.cloud</groupId>
@@ -80,15 +88,7 @@
8088

8189
<dependency>
8290
<groupId>org.springframework.boot</groupId>
83-
<artifactId>spring-boot-starter-security</artifactId>
84-
</dependency>
85-
<dependency>
86-
<groupId>org.springframework.security</groupId>
87-
<artifactId>spring-security-oauth2-jose</artifactId>
88-
</dependency>
89-
<dependency>
90-
<groupId>org.springframework.security</groupId>
91-
<artifactId>spring-security-oauth2-resource-server</artifactId>
91+
<artifactId>spring-boot-starter-security-oauth2-resource-server</artifactId>
9292
</dependency>
9393

9494
<dependency>
@@ -101,8 +101,8 @@
101101
<artifactId>spring-boot-starter-data-jpa</artifactId>
102102
</dependency>
103103
<dependency>
104-
<groupId>org.flywaydb</groupId>
105-
<artifactId>flyway-core</artifactId>
104+
<groupId>org.springframework.boot</groupId>
105+
<artifactId>spring-boot-starter-flyway</artifactId>
106106
</dependency>
107107
<!-- required module since Flyway 10 (Spring Boot 3.3) -->
108108
<dependency>
@@ -114,7 +114,6 @@
114114
<dependency>
115115
<groupId>io.netty</groupId>
116116
<artifactId>netty-resolver-dns-native-macos</artifactId>
117-
<version>${netty.version}</version>
118117
<classifier>osx-aarch_64</classifier>
119118
</dependency>
120119

@@ -133,7 +132,7 @@
133132
<dependency>
134133
<groupId>digital.pragmatech.testing</groupId>
135134
<artifactId>spring-test-profiler</artifactId>
136-
<version>0.0.13</version>
135+
<version>0.0.15</version>
137136
<scope>test</scope>
138137
</dependency>
139138
<dependency>
@@ -142,8 +141,38 @@
142141
<scope>test</scope>
143142
</dependency>
144143
<dependency>
145-
<groupId>org.springframework.security</groupId>
146-
<artifactId>spring-security-test</artifactId>
144+
<groupId>org.springframework.boot</groupId>
145+
<artifactId>spring-boot-starter-validation-test</artifactId>
146+
<scope>test</scope>
147+
</dependency>
148+
<dependency>
149+
<groupId>org.springframework.boot</groupId>
150+
<artifactId>spring-boot-starter-webclient-test</artifactId>
151+
<scope>test</scope>
152+
</dependency>
153+
<dependency>
154+
<groupId>org.springframework.boot</groupId>
155+
<artifactId>spring-boot-starter-restclient-test</artifactId>
156+
<scope>test</scope>
157+
</dependency>
158+
<dependency>
159+
<groupId>org.springframework.boot</groupId>
160+
<artifactId>spring-boot-starter-webflux-test</artifactId>
161+
<scope>test</scope>
162+
</dependency>
163+
<dependency>
164+
<groupId>org.springframework.boot</groupId>
165+
<artifactId>spring-boot-starter-webmvc-test</artifactId>
166+
<scope>test</scope>
167+
</dependency>
168+
<dependency>
169+
<groupId>org.springframework.boot</groupId>
170+
<artifactId>spring-boot-starter-security-test</artifactId>
171+
<scope>test</scope>
172+
</dependency>
173+
<dependency>
174+
<groupId>org.springframework.boot</groupId>
175+
<artifactId>spring-boot-starter-security-oauth2-resource-server-test</artifactId>
147176
<scope>test</scope>
148177
</dependency>
149178
<!-- No longer required, recent Mockito version include it -->
@@ -154,22 +183,22 @@
154183
</dependency> -->
155184
<dependency>
156185
<groupId>org.testcontainers</groupId>
157-
<artifactId>postgresql</artifactId>
186+
<artifactId>testcontainers-postgresql</artifactId>
158187
<scope>test</scope>
159188
</dependency>
160189
<dependency>
161190
<groupId>org.testcontainers</groupId>
162-
<artifactId>junit-jupiter</artifactId>
191+
<artifactId>testcontainers-junit-jupiter</artifactId>
163192
<scope>test</scope>
164193
</dependency>
165194
<dependency>
166195
<groupId>org.testcontainers</groupId>
167-
<artifactId>localstack</artifactId>
196+
<artifactId>testcontainers-localstack</artifactId>
168197
<scope>test</scope>
169198
</dependency>
170199
<dependency>
171200
<groupId>org.testcontainers</groupId>
172-
<artifactId>selenium</artifactId>
201+
<artifactId>testcontainers-selenium</artifactId>
173202
<scope>test</scope>
174203
</dependency>
175204

@@ -191,6 +220,21 @@
191220
<artifactId>awaitility</artifactId>
192221
<scope>test</scope>
193222
</dependency>
223+
<dependency>
224+
<groupId>org.springframework.boot</groupId>
225+
<artifactId>spring-boot-starter-actuator-test</artifactId>
226+
<scope>test</scope>
227+
</dependency>
228+
<dependency>
229+
<groupId>org.springframework.boot</groupId>
230+
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
231+
<scope>test</scope>
232+
</dependency>
233+
<dependency>
234+
<groupId>org.springframework.boot</groupId>
235+
<artifactId>spring-boot-starter-flyway-test</artifactId>
236+
<scope>test</scope>
237+
</dependency>
194238
<dependency>
195239
<groupId>com.squareup.okhttp3</groupId>
196240
<artifactId>mockwebserver</artifactId>
@@ -199,7 +243,6 @@
199243
<dependency>
200244
<groupId>org.apache.commons</groupId>
201245
<artifactId>commons-lang3</artifactId>
202-
<version>${commons-lang3.version}</version>
203246
<scope>test</scope>
204247
</dependency>
205248
<!-- Required for tests due to dependency with the AWS SDK v1 !-->
@@ -237,7 +280,6 @@
237280
<plugin>
238281
<groupId>org.apache.maven.plugins</groupId>
239282
<artifactId>maven-surefire-plugin</artifactId>
240-
<version>3.5.3</version>
241283
<configuration>
242284
<properties>
243285
<configurationParameters>
@@ -251,7 +293,6 @@
251293
<plugin>
252294
<groupId>org.apache.maven.plugins</groupId>
253295
<artifactId>maven-failsafe-plugin</artifactId>
254-
<version>3.5.4</version>
255296
<configuration>
256297
<includes>
257298
<include>**/*IT.java</include>

src/main/java/de/rieckpil/courses/book/management/Book.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
import java.util.Objects;
44

55
import com.fasterxml.jackson.annotation.JsonIgnore;
6-
import jakarta.persistence.*;
6+
import jakarta.persistence.Column;
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.GeneratedValue;
9+
import jakarta.persistence.GenerationType;
10+
import jakarta.persistence.Id;
11+
import jakarta.persistence.Table;
712
import org.hibernate.annotations.NaturalId;
813

914
@Entity
@@ -18,7 +23,9 @@ public class Book {
1823
@Column(nullable = false)
1924
private String title;
2025

21-
@NaturalId private String isbn;
26+
@NaturalId
27+
@Column(nullable = false)
28+
private String isbn;
2229

2330
private String author;
2431

@@ -106,8 +113,12 @@ public void setPages(Long pages) {
106113

107114
@Override
108115
public boolean equals(Object o) {
109-
if (this == o) return true;
110-
if (!(o instanceof Book)) return false;
116+
if (this == o) {
117+
return true;
118+
}
119+
if (!(o instanceof Book)) {
120+
return false;
121+
}
111122
Book book = (Book) o;
112123
return Objects.equals(isbn, book.getIsbn());
113124
}

src/main/java/de/rieckpil/courses/book/management/OpenLibraryApiClient.java

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

33
import java.time.Duration;
44

5-
import com.fasterxml.jackson.databind.JsonNode;
6-
import com.fasterxml.jackson.databind.node.ObjectNode;
75
import org.springframework.stereotype.Component;
86
import org.springframework.web.reactive.function.client.WebClient;
97
import reactor.util.retry.Retry;
8+
import tools.jackson.databind.JsonNode;
9+
import tools.jackson.databind.node.ObjectNode;
1010

1111
@Component
1212
public class OpenLibraryApiClient {
@@ -43,16 +43,17 @@ public Book fetchMetadataForBook(String isbn) {
4343
private Book convertToBook(String isbn, JsonNode content) {
4444
Book book = new Book();
4545
book.setIsbn(isbn);
46-
book.setThumbnailUrl(content.get("cover").get("small").asText());
47-
book.setTitle(content.get("title").asText());
48-
book.setAuthor(content.get("authors").get(0).get("name").asText());
49-
book.setPublisher(content.get("publishers").get(0).get("name").asText("n.A."));
46+
book.setThumbnailUrl(content.get("cover").get("small").asString());
47+
book.setTitle(content.get("title").asString());
48+
book.setAuthor(content.get("authors").get(0).get("name").asString());
49+
book.setPublisher(content.get("publishers").get(0).get("name").asString("n.A."));
5050
book.setPages(content.get("number_of_pages").asLong(0));
51-
book.setDescription(content.get("notes") == null ? "n.A" : content.get("notes").asText("n.A."));
51+
book.setDescription(
52+
content.get("notes") == null ? "n.A" : content.get("notes").asString("n.A."));
5253
book.setGenre(
5354
content.get("subjects") == null
5455
? "n.A"
55-
: content.get("subjects").get(0).get("name").asText("n.A."));
56+
: content.get("subjects").get(0).get("name").asString("n.A."));
5657
return book;
5758
}
5859
}

src/main/java/de/rieckpil/courses/book/management/OpenLibraryRestTemplateApiClient.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
import java.time.Duration;
44
import java.util.Collections;
55

6-
import com.fasterxml.jackson.databind.JsonNode;
7-
import com.fasterxml.jackson.databind.node.ObjectNode;
8-
import org.springframework.boot.web.client.RestTemplateBuilder;
6+
import org.springframework.boot.restclient.RestTemplateBuilder;
97
import org.springframework.http.HttpEntity;
108
import org.springframework.http.HttpHeaders;
119
import org.springframework.http.HttpMethod;
1210
import org.springframework.http.MediaType;
1311
import org.springframework.stereotype.Component;
1412
import org.springframework.web.client.RestTemplate;
13+
import tools.jackson.databind.JsonNode;
14+
import tools.jackson.databind.node.ObjectNode;
1515

1616
@Component
1717
public class OpenLibraryRestTemplateApiClient {
@@ -22,8 +22,8 @@ public OpenLibraryRestTemplateApiClient(RestTemplateBuilder restTemplateBuilder)
2222
this.restTemplate =
2323
restTemplateBuilder
2424
.rootUri("https://openlibrary.org")
25-
.setConnectTimeout(Duration.ofSeconds(2))
26-
.setReadTimeout(Duration.ofSeconds(2))
25+
.clientSettings(
26+
settings -> settings.withTimeouts(Duration.ofSeconds(2), Duration.ofSeconds(2)))
2727
.build();
2828
}
2929

@@ -54,16 +54,17 @@ public Book fetchMetadataForBook(String isbn) {
5454
private Book convertToBook(String isbn, JsonNode content) {
5555
Book book = new Book();
5656
book.setIsbn(isbn);
57-
book.setThumbnailUrl(content.get("cover").get("small").asText());
58-
book.setTitle(content.get("title").asText());
59-
book.setAuthor(content.get("authors").get(0).get("name").asText());
60-
book.setPublisher(content.get("publishers").get(0).get("name").asText("n.A."));
57+
book.setThumbnailUrl(content.get("cover").get("small").asString());
58+
book.setTitle(content.get("title").asString());
59+
book.setAuthor(content.get("authors").get(0).get("name").asString());
60+
book.setPublisher(content.get("publishers").get(0).get("name").asString("n.A."));
6161
book.setPages(content.get("number_of_pages").asLong(0));
62-
book.setDescription(content.get("notes") == null ? "n.A" : content.get("notes").asText("n.A."));
62+
book.setDescription(
63+
content.get("notes") == null ? "n.A" : content.get("notes").asString("n.A."));
6364
book.setGenre(
6465
content.get("subjects") == null
6566
? "n.A"
66-
: content.get("subjects").get(0).get("name").asText("n.A."));
67+
: content.get("subjects").get(0).get("name").asString("n.A."));
6768
return book;
6869
}
6970
}

src/main/java/de/rieckpil/courses/book/review/ReviewController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package de.rieckpil.courses.book.review;
22

3-
import com.fasterxml.jackson.databind.node.ArrayNode;
4-
import com.fasterxml.jackson.databind.node.ObjectNode;
53
import jakarta.validation.Valid;
64
import org.springframework.http.ResponseEntity;
75
import org.springframework.security.access.prepost.PreAuthorize;
@@ -10,6 +8,8 @@
108
import org.springframework.web.bind.annotation.*;
119
import org.springframework.web.util.UriComponents;
1210
import org.springframework.web.util.UriComponentsBuilder;
11+
import tools.jackson.databind.node.ArrayNode;
12+
import tools.jackson.databind.node.ObjectNode;
1313

1414
@Validated
1515
@RestController

0 commit comments

Comments
 (0)