Skip to content

Commit c50e42f

Browse files
authored
Merge pull request #234 from nanotaboada/copilot/upgrade-spring-boot-4-jdk-25
feat: upgrade to Spring Boot 4.0 and JDK 25 LTS
2 parents 6f38258 + 5936c65 commit c50e42f

9 files changed

Lines changed: 251 additions & 198 deletions

File tree

.github/copilot-instructions.md

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Project Overview
44

5-
This is a RESTful Web Service proof-of-concept built with **Spring Boot 3** targeting **JDK 21 (LTS)**. The application demonstrates a clean, layered architecture implementing a CRUD API for managing books. It uses an in-memory H2 database for data persistence and includes comprehensive test coverage.
5+
This is a RESTful Web Service proof-of-concept built with **Spring Boot 4** targeting **JDK 25 (LTS)**. The application demonstrates a clean, layered architecture implementing a CRUD API for managing books. It uses an in-memory H2 database for data persistence and includes comprehensive test coverage.
66

77
**Key URLs:**
88

@@ -14,8 +14,8 @@ This is a RESTful Web Service proof-of-concept built with **Spring Boot 3** targ
1414

1515
### Core Framework & Runtime
1616

17-
- **Java**: JDK 21 (LTS) - use modern Java features where appropriate
18-
- **Spring Boot**: 3.4.4 with starter dependencies (Web, Data JPA, Validation, Cache, Actuator)
17+
- **Java**: JDK 25 (LTS) - use modern Java features where appropriate
18+
- **Spring Boot**: 4.0.0 with modular starter dependencies (WebMVC, Data JPA, Validation, Cache, Actuator)
1919
- **Build Tool**: Maven 3.9+ (use `./mvnw` wrapper, NOT system Maven)
2020
- **Database**: H2 in-memory database (runtime scope)
2121

@@ -31,15 +31,14 @@ This is a RESTful Web Service proof-of-concept built with **Spring Boot 3** targ
3131

3232
- **JUnit 5** (Jupiter): Test framework
3333
- **Mockito**: Mocking framework
34-
- **Spring Boot Test**: `@WebMvcTest`, `@DataJpaTest`, etc.
34+
- **Spring Boot Test**: `@WebMvcTest`, `@DataJpaTest`, `@AutoConfigureCache`, etc.
3535
- **AssertJ**: Preferred assertion library (use over standard JUnit assertions)
3636

3737
### DevOps & CI/CD
3838

3939
- **Docker**: Multi-stage build with Eclipse Temurin Alpine images
4040
- **Docker Compose**: Local containerized deployment
4141
- **GitHub Actions**: CI pipeline with coverage reporting (Codecov, Codacy)
42-
- **Azure Pipelines**: Alternative CI configuration
4342

4443
## Project Structure
4544

@@ -90,17 +89,18 @@ scripts/
9089

9190
- **Lombok**: Prefer `@Data`, `@RequiredArgsConstructor`, `@NoArgsConstructor`, `@AllArgsConstructor` over manual code
9291
- **Streams**: Use Java Streams API for collection processing (see `BooksService.retrieveAll()`)
93-
- **Modern Java**: Leverage JDK 21 features (records, pattern matching, etc.) where beneficial
92+
- **Modern Java**: Leverage JDK 25 features (records, pattern matching, sealed classes, etc.) where beneficial
9493
- **Comments**: Section dividers used in controllers/services (e.g., `/* HTTP POST */`)
9594

9695
### Testing Conventions
9796

9897
- **Test Class Naming**: `<ClassName>Tests` (plural, e.g., `BooksControllerTests`)
9998
- **Test Method Naming**: `given<Condition>_when<Action>_then<Expected>` (BDD style)
10099
- **Assertions**: Use AssertJ fluent assertions (`assertThat(...).isEqualTo(...)`)
101-
- **Mocking**: Use `@MockBean` for Spring beans, verify interactions with `verify()`
100+
- **Mocking**: Use `@MockitoBean` for Spring beans (new in Spring Boot 4.0), verify interactions with `verify()`
102101
- **Test Data**: Use fake data factories (`BookFakes`, `BookDTOFakes`) for consistent test data
103102
- **Display Names**: Use `@DisplayName` for readable test descriptions
103+
- **Caching in Tests**: Add `@AutoConfigureCache` to slice tests (`@WebMvcTest`, `@DataJpaTest`) when caching is needed
104104

105105
### Coverage Exclusions
106106

@@ -137,8 +137,8 @@ JaCoCo excludes from coverage (see `pom.xml` and `codecov.yml`):
137137
**Critical Requirements**:
138138

139139
- **ALWAYS use `./mvnw` wrapper** (Unix/macOS) or `mvnw.cmd` (Windows), NOT `mvn`
140-
- **JDK 21 is REQUIRED**: The project targets JDK 21 (LTS). Using newer JDKs (22+) will cause Mockito/ByteBuddy compatibility issues in tests
141-
- **JAVA_HOME must be set**: Maven wrapper requires JAVA_HOME pointing to JDK 21 installation
140+
- **JDK 25 is REQUIRED**: The project targets JDK 25 (LTS)
141+
- **JAVA_HOME must be set**: Maven wrapper requires JAVA_HOME pointing to JDK 25 installation
142142

143143
### Docker Commands
144144

@@ -205,8 +205,8 @@ docker compose logs -f
205205
- **Lombok not working**: Ensure annotation processor is enabled in IDE and `maven-compiler-plugin` includes Lombok path
206206
- **Tests failing**: Check if H2 database is properly initialized; review `BooksDataInitializer.seed()`
207207
- **Port already in use**: Change `server.port` in `application.properties` or kill process using ports 9000/9001
208-
- **JAVA_HOME not set**: Run `export JAVA_HOME=$(/usr/libexec/java_home -v 21)` on macOS or set to JDK 21 path on other systems
209-
- **JDK version errors**: Project requires JDK 21 (LTS). Using JDK 22+ causes Mockito/ByteBuddy failures like "Java 25 (69) is not supported"
208+
- **JAVA_HOME not set**: Run `export JAVA_HOME=$(/usr/libexec/java_home -v 25)` on macOS or set to JDK 25 path on other systems
209+
- **CacheManager errors in tests**: Add `@AutoConfigureCache` annotation to slice tests (`@WebMvcTest`, `@DataJpaTest`)
210210

211211
### Docker Issues
212212

@@ -216,10 +216,10 @@ docker compose logs -f
216216
### Common Pitfalls
217217

218218
- **Don't use system Maven**: Always use `./mvnw` wrapper
219-
- **Don't use newer JDKs**: Stick to JDK 21 - newer versions break Mockito in tests
220219
- **Don't modify `Application.java` coverage**: It's excluded by design
221220
- **Don't test Lombok-generated code**: Focus on business logic
222221
- **Repository interfaces**: Custom query methods may not show in coverage (JaCoCo limitation)
222+
- **Spring Boot 4.0 modular packages**: Test annotations like `@WebMvcTest`, `@DataJpaTest`, and `@AutoConfigureCache` are now in modular packages (e.g., `org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest`)
223223

224224
## CI/CD Pipeline
225225

@@ -235,11 +235,6 @@ docker compose logs -f
235235
- `CODACY_PROJECT_TOKEN`: Codacy integration token
236236
- `GITHUB_TOKEN`: Automatically provided for GHCR push
237237

238-
### Azure Pipelines (`azure-pipelines.yml`)
239-
240-
- Runs on `ubuntu-latest` with JDK 21
241-
- Executes `mvn package` and publishes test results
242-
243238
## Contributing
244239

245240
Follow [Conventional Commits](https://www.conventionalcommits.org/):

.github/workflows/maven.yml

Lines changed: 90 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,99 +4,99 @@
44
name: Java CI
55

66
permissions:
7-
contents: read
7+
contents: read
88

99
on:
10-
push:
11-
branches: [master]
12-
pull_request:
13-
branches: [master]
10+
push:
11+
branches: [master]
12+
pull_request:
13+
branches: [master]
1414

1515
env:
16-
JAVA_VERSION: 21
16+
JAVA_VERSION: 25
1717

1818
jobs:
19-
verify:
20-
runs-on: ubuntu-latest
21-
steps:
22-
- name: Checkout repository
23-
uses: actions/checkout@v6.0.0
24-
25-
- name: Set up OpenJDK ${{ env.JAVA_VERSION }}
26-
uses: actions/setup-java@v5.0.0
27-
with:
28-
java-version: ${{ env.JAVA_VERSION }}
29-
distribution: "temurin"
30-
cache: "maven"
31-
32-
- name: Compile and verify with Maven
33-
run: mvn verify --file pom.xml
34-
35-
- name: Upload JaCoCo coverage report artifact
36-
uses: actions/upload-artifact@v5.0.0
37-
with:
38-
name: jacoco.xml
39-
path: ./target/site/jacoco/jacoco.xml
40-
41-
coverage:
42-
needs: verify
43-
runs-on: ubuntu-latest
44-
strategy:
45-
matrix:
46-
service: [codecov, codacy]
47-
steps:
48-
- name: Checkout repository
49-
uses: actions/checkout@v6.0.0
50-
51-
- name: Download JaCoCo coverage report artifact
52-
uses: actions/download-artifact@v6.0.0
53-
with:
54-
name: jacoco.xml
55-
56-
- name: Upload JaCoCo coverage report to Codecov
57-
if: matrix.service == 'codecov'
58-
uses: codecov/codecov-action@v5.5.1
59-
with:
60-
token: ${{ secrets.CODECOV_TOKEN }}
61-
files: jacoco.xml
62-
63-
- name: Upload JaCoCo coverage report to Codacy
64-
if: matrix.service == 'codacy'
65-
uses: codacy/codacy-coverage-reporter-action@v1.3.0
66-
with:
67-
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
68-
force-coverage-parser: jacoco -r jacoco.xml
69-
70-
container:
71-
needs: coverage
72-
runs-on: ubuntu-latest
73-
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
74-
75-
permissions:
76-
contents: read
77-
packages: write
78-
79-
steps:
80-
- name: Checkout repository
81-
uses: actions/checkout@v6.0.0
82-
83-
- name: Log in to GitHub Container Registry
84-
uses: docker/login-action@v3.6.0
85-
with:
86-
registry: ghcr.io
87-
username: ${{ github.actor }}
88-
password: ${{ secrets.GITHUB_TOKEN }}
89-
90-
- name: Set up Docker Buildx
91-
uses: docker/setup-buildx-action@v3.11.1
92-
93-
- name: Build and push Docker image to GitHub Container Registry
94-
uses: docker/build-push-action@v6.18.0
95-
with:
96-
context: .
97-
push: true
98-
platforms: linux/amd64
99-
provenance: false
100-
tags: |
101-
ghcr.io/${{ github.repository }}:latest
102-
ghcr.io/${{ github.repository }}:sha-${{ github.sha }}
19+
verify:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v6.0.0
24+
25+
- name: Set up OpenJDK ${{ env.JAVA_VERSION }}
26+
uses: actions/setup-java@v5.0.0
27+
with:
28+
java-version: ${{ env.JAVA_VERSION }}
29+
distribution: "temurin"
30+
cache: "maven"
31+
32+
- name: Compile and verify with Maven
33+
run: mvn verify --file pom.xml
34+
35+
- name: Upload JaCoCo coverage report artifact
36+
uses: actions/upload-artifact@v5.0.0
37+
with:
38+
name: jacoco.xml
39+
path: ./target/site/jacoco/jacoco.xml
40+
41+
coverage:
42+
needs: verify
43+
runs-on: ubuntu-latest
44+
strategy:
45+
matrix:
46+
service: [codecov, codacy]
47+
steps:
48+
- name: Checkout repository
49+
uses: actions/checkout@v6.0.0
50+
51+
- name: Download JaCoCo coverage report artifact
52+
uses: actions/download-artifact@v6.0.0
53+
with:
54+
name: jacoco.xml
55+
56+
- name: Upload JaCoCo coverage report to Codecov
57+
if: matrix.service == 'codecov'
58+
uses: codecov/codecov-action@v5.5.1
59+
with:
60+
token: ${{ secrets.CODECOV_TOKEN }}
61+
files: jacoco.xml
62+
63+
- name: Upload JaCoCo coverage report to Codacy
64+
if: matrix.service == 'codacy'
65+
uses: codacy/codacy-coverage-reporter-action@v1.3.0
66+
with:
67+
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
68+
force-coverage-parser: jacoco -r jacoco.xml
69+
70+
container:
71+
needs: coverage
72+
runs-on: ubuntu-latest
73+
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
74+
75+
permissions:
76+
contents: read
77+
packages: write
78+
79+
steps:
80+
- name: Checkout repository
81+
uses: actions/checkout@v6.0.0
82+
83+
- name: Log in to GitHub Container Registry
84+
uses: docker/login-action@v3.6.0
85+
with:
86+
registry: ghcr.io
87+
username: ${{ github.actor }}
88+
password: ${{ secrets.GITHUB_TOKEN }}
89+
90+
- name: Set up Docker Buildx
91+
uses: docker/setup-buildx-action@v3.11.1
92+
93+
- name: Build and push Docker image to GitHub Container Registry
94+
uses: docker/build-push-action@v6.18.0
95+
with:
96+
context: .
97+
push: true
98+
platforms: linux/amd64
99+
provenance: false
100+
tags: |
101+
ghcr.io/${{ github.repository }}:latest
102+
ghcr.io/${{ github.repository }}:sha-${{ github.sha }}

.java-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
21
1+
25

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Stage 1: Builder
33
# This stage builds the application and its dependencies.
44
# ------------------------------------------------------------------------------
5-
FROM maven:3.9-eclipse-temurin-21-alpine AS builder
5+
FROM maven:3.9-eclipse-temurin-25-alpine AS builder
66

77
WORKDIR /app
88

@@ -19,7 +19,7 @@ RUN mvn clean package -DskipTests
1919
# Stage 2: Runtime
2020
# This stage creates the final, minimal image to run the application.
2121
# ------------------------------------------------------------------------------
22-
FROM eclipse-temurin:21-jdk-alpine AS runtime
22+
FROM eclipse-temurin:25-jdk-alpine AS runtime
2323

2424
WORKDIR /app
2525

@@ -28,7 +28,7 @@ RUN apk add --no-cache curl
2828

2929
# Metadata labels for the image. These are useful for registries and inspection.
3030
LABEL org.opencontainers.image.title="🧪 RESTful Web Service with Spring Boot"
31-
LABEL org.opencontainers.image.description="Proof of Concept for a RESTful Web Service made with JDK 21 (LTS) and Spring Boot 3"
31+
LABEL org.opencontainers.image.description="Proof of Concept for a RESTful Web Service made with JDK 25 (LTS) and Spring Boot 4"
3232
LABEL org.opencontainers.image.licenses="MIT"
3333
LABEL org.opencontainers.image.source="https://github.com/nanotaboada/java.samples.spring.boot"
3434

README.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![CodeFactor](https://www.codefactor.io/repository/github/nanotaboada/java.samples.spring.boot/badge)](https://www.codefactor.io/repository/github/nanotaboada/java.samples.spring.boot)
88
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
99

10-
> A production-ready RESTful Web Service demonstrating clean architecture patterns with Spring Boot 3, comprehensive testing, and containerized deployment.
10+
> A production-ready RESTful Web Service demonstrating clean architecture patterns with Spring Boot 4, comprehensive testing, and containerized deployment.
1111
1212
## Table of Contents
1313

@@ -26,7 +26,7 @@
2626

2727
## About
2828

29-
A proof-of-concept RESTful Web Service built with **Spring Boot 3** targeting **JDK 21 (LTS)**. This project demonstrates best practices for building a layered, testable, and maintainable API implementing CRUD operations for a Books resource.
29+
A proof-of-concept RESTful Web Service built with **Spring Boot 4** targeting **JDK 25 (LTS)**. This project demonstrates best practices for building a layered, testable, and maintainable API implementing CRUD operations for a Books resource.
3030

3131
The service showcases:
3232

@@ -48,7 +48,7 @@ The service showcases:
4848
-**Health Monitoring** - Spring Boot Actuator endpoints
4949
-**Test Coverage** - JaCoCo reports with Codecov/Codacy integration
5050
-**Docker Support** - Multi-stage builds with Eclipse Temurin Alpine images
51-
-**CI/CD Ready** - GitHub Actions and Azure Pipelines configurations
51+
-**CI/CD Ready** - GitHub Actions with automated testing and container builds
5252

5353
## Architecture
5454

@@ -66,16 +66,15 @@ _Figure: Simplified, conceptual project structure and main application flow. Not
6666

6767
Before you begin, ensure you have the following installed:
6868

69-
- **Java Development Kit (JDK) 21** - [Download](https://adoptium.net/temurin/releases/?version=21)
70-
- ⚠️ **Critical**: JDK 21 is required. Newer versions (22+) cause Mockito/ByteBuddy compatibility issues.
69+
- **Java Development Kit (JDK) 25** - [Download](https://adoptium.net/temurin/releases/?version=25)
7170
- Verify with: `java -version`
7271
- **Maven 3.9+** (optional) - Project includes Maven wrapper (`./mvnw`)
7372
- **Docker** (optional) - For containerized deployment
7473

7574
**macOS Users**: Set `JAVA_HOME` if needed:
7675

7776
```bash
78-
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
77+
export JAVA_HOME=$(/usr/libexec/java_home -v 25)
7978
```
8079

8180
## Getting Started
@@ -180,8 +179,8 @@ open target/site/jacoco/index.html
180179

181180
**Test Structure:**
182181

183-
- **Unit Tests** - `@WebMvcTest`, `@DataJpaTest` for isolated layer testing
184-
- **Mocking** - Mockito for dependency mocking
182+
- **Unit Tests** - `@WebMvcTest`, `@DataJpaTest` for isolated layer testing (with `@AutoConfigureCache` for caching support)
183+
- **Mocking** - Mockito with `@MockitoBean` for dependency mocking
185184
- **Assertions** - AssertJ fluent assertions
186185
- **Naming Convention** - BDD style: `given<Condition>_when<Action>_then<Expected>`
187186

0 commit comments

Comments
 (0)