spring-boot4-skill 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -4
- package/lib/generator.js +4 -2
- package/package.json +1 -1
- package/skills/java-spring-framework/SKILL.md +28 -0
- package/skills/java-spring-framework/references/spring-boot-4.md +83 -7
- package/skills/java-spring-framework/references/spring-framework-7.md +2 -0
- package/skills/java-spring-framework/references/spring-modulith.md +13 -0
- package/skills/java-spring-framework/references/spring-security-7.md +203 -0
- package/skills/java-spring-framework/references/troubleshooting-migration.md +119 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Spring Boot 4 · Java 25 · Spring Framework 7
|
|
2
2
|
|
|
3
3
|
> **2026-standard** project scaffolder + Claude Code AI skill for Java / Spring development.
|
|
4
|
-
> By [AyrtonAldayr](https://github.com/AyrtonAldayr)
|
|
4
|
+
> By [AyrtonAldayr](https://github.com/AyrtonAldayr) · **v1.1.0**
|
|
5
5
|
|
|
6
6
|
This repository provides two tools in one:
|
|
7
7
|
|
|
@@ -70,7 +70,26 @@ After answering a few prompts, you get a complete project with:
|
|
|
70
70
|
|
|
71
71
|
Install the skill to get AI assistance aligned with Spring Boot 4 / Framework 7 standards.
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
There are **two common ways** to install it, depending on which tool you use:
|
|
74
|
+
|
|
75
|
+
### Option 1 — npx (Skills CLI, multi-agent)
|
|
76
|
+
|
|
77
|
+
Uses the open [Skills CLI](https://github.com/vercel-labs/skills) (`npx skills`). Works with Claude Code, Cursor, Codex, and other agents that follow the same skill layout.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Install the skill (prompts for which agent(s) to install to)
|
|
81
|
+
npx skills add AyrtonAldayr/agent-skill-java-spring-framework --skill java-spring-framework
|
|
82
|
+
|
|
83
|
+
# Install only for Claude Code
|
|
84
|
+
npx skills add AyrtonAldayr/agent-skill-java-spring-framework --skill java-spring-framework -a claude-code
|
|
85
|
+
|
|
86
|
+
# Install for Cursor
|
|
87
|
+
npx skills add AyrtonAldayr/agent-skill-java-spring-framework --skill java-spring-framework -a cursor
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Option 2 — Claude Code official CLI
|
|
91
|
+
|
|
92
|
+
If you use the `claude` CLI (Anthropic’s Claude Code), you can install directly from GitHub:
|
|
74
93
|
|
|
75
94
|
```bash
|
|
76
95
|
claude skills install github:AyrtonAldayr/agent-skill-java-spring-framework
|
|
@@ -93,9 +112,11 @@ Once installed, Claude Code acts as a **Senior Spring Boot 4 architect**:
|
|
|
93
112
|
| File | Contents |
|
|
94
113
|
|---|---|
|
|
95
114
|
| `skills/java-spring-framework/references/spring-framework-7.md` | All Spring 7 APIs with code examples |
|
|
96
|
-
| `skills/java-spring-framework/references/spring-boot-4.md` | Boot 4
|
|
97
|
-
| `skills/java-spring-framework/references/spring-
|
|
115
|
+
| `skills/java-spring-framework/references/spring-boot-4.md` | Boot 4: native, virtual threads, testing (Testcontainers), reactive stack |
|
|
116
|
+
| `skills/java-spring-framework/references/spring-security-7.md` | OAuth2 Resource Server, JWT, method security, CORS |
|
|
117
|
+
| `skills/java-spring-framework/references/spring-modulith.md` | Module structure, events, integration testing, common pitfalls |
|
|
98
118
|
| `skills/java-spring-framework/references/build-templates.md` | Complete Gradle KTS + Maven POM templates |
|
|
119
|
+
| `skills/java-spring-framework/references/troubleshooting-migration.md` | Common errors (javax/jakarta, RestTemplate), Boot 3→4 checklist |
|
|
99
120
|
|
|
100
121
|
---
|
|
101
122
|
|
package/lib/generator.js
CHANGED
|
@@ -179,9 +179,11 @@ ${chalk.bold('Next steps:')}
|
|
|
179
179
|
${chalk.cyan(cd)}
|
|
180
180
|
${chalk.cyan(run)}
|
|
181
181
|
|
|
182
|
-
${chalk.bold('Install the AI coding skill:')}
|
|
182
|
+
${chalk.bold('Install the AI coding skill (optional):')}
|
|
183
183
|
|
|
184
|
-
${chalk.cyan(
|
|
184
|
+
${chalk.cyan('npx skills add AyrtonAldayr/agent-skill-java-spring-framework --skill java-spring-framework')}
|
|
185
|
+
${chalk.dim('or')}
|
|
186
|
+
${chalk.cyan('claude skills install github:AyrtonAldayr/agent-skill-java-spring-framework')}
|
|
185
187
|
|
|
186
188
|
${chalk.dim('Docs: https://github.com/AyrtonAldayr/agent-skill-java-spring-framework')}
|
|
187
189
|
`);
|
package/package.json
CHANGED
|
@@ -16,6 +16,32 @@ description: >
|
|
|
16
16
|
You are a Senior Java & Spring Boot 4 / Spring Framework 7 architect. All code must be
|
|
17
17
|
idiomatic for **2026 standards**: Spring Boot 4.0.x, Spring Framework 7.0.x, Java 25, Jakarta EE 11.
|
|
18
18
|
|
|
19
|
+
**Triggers:** REST APIs, microservices, JdbcClient/JPA 3.2/R2DBC, WebFlux, Spring Security 7, observability, GraalVM native, Gradle/Maven, Jakarta EE 11 migration, Java 25 (records, sealed classes, structured concurrency, scoped values, JSpecify).
|
|
20
|
+
|
|
21
|
+
## When NOT to use this skill
|
|
22
|
+
|
|
23
|
+
- Legacy Spring Boot 2.x or 3.x with no upgrade plan to Boot 4 / Framework 7.
|
|
24
|
+
- Non-Spring JVM stacks (Quarkus, Micronaut, Helidon) unless the user explicitly asks for Spring comparison or migration.
|
|
25
|
+
- Tasks that do not touch Java/Spring backend (e.g. only frontend, only infra/DevOps with no Spring code).
|
|
26
|
+
- General Java questions with no Spring or framework context.
|
|
27
|
+
|
|
28
|
+
## Quick decision (which reference to load first)
|
|
29
|
+
|
|
30
|
+
```mermaid
|
|
31
|
+
flowchart TD
|
|
32
|
+
A[User request] --> B{REST blocking or reactive?}
|
|
33
|
+
B -->|Blocking MVC + JDBC/JPA| C[spring-boot-4.md + spring-framework-7.md]
|
|
34
|
+
B -->|Reactive WebFlux + R2DBC| D[spring-boot-4.md Reactive section + spring-framework-7.md]
|
|
35
|
+
A --> E{Modular monolith?}
|
|
36
|
+
E -->|Yes| F[spring-modulith.md]
|
|
37
|
+
A --> G{Security / OAuth2 / JWT?}
|
|
38
|
+
G -->|Yes| H[spring-security-7.md]
|
|
39
|
+
A --> I{Scaffold / build / versions?}
|
|
40
|
+
I -->|Yes| J[build-templates.md]
|
|
41
|
+
A --> K{Migration or errors?}
|
|
42
|
+
K -->|Yes| L[troubleshooting-migration.md]
|
|
43
|
+
```
|
|
44
|
+
|
|
19
45
|
## Mandatory Workflow
|
|
20
46
|
|
|
21
47
|
1. **Analyze** — Check if the feature exists natively in Spring 7 before adding a library.
|
|
@@ -52,5 +78,7 @@ Load these as needed — do not load all at once:
|
|
|
52
78
|
|---|---|---|
|
|
53
79
|
| Spring Framework 7 APIs | `references/spring-framework-7.md` | Framework-level features: versioning, resilience, JSpecify, SpEL, streaming |
|
|
54
80
|
| Spring Boot 4 features | `references/spring-boot-4.md` | Boot auto-config, Actuator, native images, testing, virtual threads |
|
|
81
|
+
| Spring Security 7 | `references/spring-security-7.md` | OAuth2 Resource Server, JWT, method security, CORS, authentication/authorization |
|
|
55
82
|
| Spring Modulith | `references/spring-modulith.md` | Domain-driven module design, event-driven architecture |
|
|
56
83
|
| Build templates | `references/build-templates.md` | Gradle KTS or Maven POM scaffolding with 2026 BOM versions |
|
|
84
|
+
| Troubleshooting & migration | `references/troubleshooting-migration.md` | Migration from Boot 3, compile/runtime errors (javax/jakarta, RestTemplate, native, null-safety) |
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
8. [Scoped Values (Java 25)](#8-scoped-values-java-25)
|
|
16
16
|
9. [Docker Compose Support](#9-docker-compose-support)
|
|
17
17
|
10. [Spring Security 7 Basics](#10-spring-security-7-basics)
|
|
18
|
+
11. [Reactive Stack (R2DBC + WebFlux)](#11-reactive-stack-r2dbc--webflux)
|
|
18
19
|
|
|
19
20
|
---
|
|
20
21
|
|
|
@@ -126,19 +127,67 @@ class UserRepositoryTest {
|
|
|
126
127
|
}
|
|
127
128
|
```
|
|
128
129
|
|
|
130
|
+
### Testcontainers (integration tests)
|
|
131
|
+
|
|
132
|
+
For full integration tests against a real database, use **Testcontainers**. Prefer this when testing repository logic, transactions, or schema; use `@MockBean` for unit/slice tests where the focus is the controller or service in isolation.
|
|
133
|
+
|
|
134
|
+
```kotlin
|
|
135
|
+
// build.gradle.kts
|
|
136
|
+
testImplementation("org.springframework.boot:spring-boot-testcontainers")
|
|
137
|
+
testImplementation("org.testcontainers:postgresql")
|
|
138
|
+
testImplementation("org.testcontainers:junit-jupiter")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```java
|
|
142
|
+
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
|
143
|
+
@Testcontainers
|
|
144
|
+
class OrderRepositoryIntegrationTest {
|
|
145
|
+
|
|
146
|
+
@Container
|
|
147
|
+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17")
|
|
148
|
+
.withDatabaseName("testdb").withUsername("test").withPassword("test");
|
|
149
|
+
|
|
150
|
+
@DynamicPropertySource
|
|
151
|
+
static void props(DynamicPropertyRegistry registry) {
|
|
152
|
+
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
153
|
+
registry.add("spring.datasource.username", postgres::getUsername);
|
|
154
|
+
registry.add("spring.datasource.password", postgres::getPassword);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@Autowired OrderRepository repository;
|
|
158
|
+
|
|
159
|
+
@Test
|
|
160
|
+
void shouldFindOrdersByUserId() {
|
|
161
|
+
// real DB; no mocks
|
|
162
|
+
List<Order> orders = repository.findByUserId("user-1");
|
|
163
|
+
assertThat(orders).isNotEmpty();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**When to use @MockBean vs Testcontainers:** Use `@MockBean` in `@WebMvcTest` or `@DataJpaTest` when you want fast, isolated tests. Use Testcontainers when you need real DB/network behavior (transactions, constraints, SQL).
|
|
169
|
+
|
|
129
170
|
---
|
|
130
171
|
|
|
131
172
|
## 4. Actuator & Observability
|
|
132
173
|
|
|
133
174
|
Spring Boot 4 ships first-class **Micrometer Tracing + OpenTelemetry** support.
|
|
134
175
|
|
|
176
|
+
### Endpoint exposure (secure by default)
|
|
177
|
+
|
|
178
|
+
Expose only what you need. In production, prefer `health` and `info` for public checks; restrict `metrics`, `prometheus`, and `traces` to an internal network or secure endpoint (e.g. via Spring Security).
|
|
179
|
+
|
|
135
180
|
```yaml
|
|
136
181
|
# application.yaml
|
|
137
182
|
management:
|
|
138
183
|
endpoints:
|
|
139
184
|
web:
|
|
140
185
|
exposure:
|
|
141
|
-
include: health,info,metrics,prometheus,traces
|
|
186
|
+
include: health,info,metrics,prometheus,traces # restrict in prod
|
|
187
|
+
base-path: /actuator
|
|
188
|
+
endpoint:
|
|
189
|
+
health:
|
|
190
|
+
show-details: when-authorized # or "never" in prod
|
|
142
191
|
tracing:
|
|
143
192
|
sampling:
|
|
144
193
|
probability: 1.0
|
|
@@ -150,13 +199,17 @@ management:
|
|
|
150
199
|
endpoint: http://otel-collector:4318/v1/traces
|
|
151
200
|
```
|
|
152
201
|
|
|
202
|
+
Protect actuator in Security 7: allow `health`/`info` for load balancers, require authentication for `metrics`/`prometheus`/`traces`. See `references/spring-security-7.md`.
|
|
203
|
+
|
|
204
|
+
### Dependencies (Micrometer + OTEL)
|
|
205
|
+
|
|
153
206
|
```kotlin
|
|
154
207
|
// build.gradle.kts
|
|
155
208
|
implementation("io.micrometer:micrometer-tracing-bridge-otel")
|
|
156
209
|
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
|
|
157
210
|
```
|
|
158
211
|
|
|
159
|
-
Custom span
|
|
212
|
+
### Custom span (Tracer)
|
|
160
213
|
|
|
161
214
|
```java
|
|
162
215
|
@Service
|
|
@@ -318,7 +371,7 @@ No manual connection properties needed — Boot auto-configures `DataSource` and
|
|
|
318
371
|
|
|
319
372
|
## 10. Spring Security 7 Basics
|
|
320
373
|
|
|
321
|
-
|
|
374
|
+
Spring Security 7 uses **lambda DSL** only for `SecurityFilterChain` and related config. Minimal example:
|
|
322
375
|
|
|
323
376
|
```java
|
|
324
377
|
@Configuration
|
|
@@ -332,10 +385,8 @@ public class SecurityConfig {
|
|
|
332
385
|
.requestMatchers("/api/public/**").permitAll()
|
|
333
386
|
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
|
334
387
|
.anyRequest().authenticated())
|
|
335
|
-
.oauth2ResourceServer(oauth2 -> oauth2
|
|
336
|
-
|
|
337
|
-
.sessionManagement(session -> session
|
|
338
|
-
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
388
|
+
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.decoder(jwtDecoder())))
|
|
389
|
+
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
339
390
|
.build();
|
|
340
391
|
}
|
|
341
392
|
|
|
@@ -345,3 +396,28 @@ public class SecurityConfig {
|
|
|
345
396
|
}
|
|
346
397
|
}
|
|
347
398
|
```
|
|
399
|
+
|
|
400
|
+
For **OAuth2 Resource Server (JWT)**, **method security (`@PreAuthorize`)**, and **CORS**, load `references/spring-security-7.md`.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## 11. Reactive Stack (R2DBC + WebFlux)
|
|
405
|
+
|
|
406
|
+
Choose the reactive stack when you need non-blocking I/O end-to-end (high concurrency, streaming, or integration with reactive drivers). For typical CRUD APIs with blocking JDBC/JPA, prefer **Spring MVC + virtual threads** (section 6).
|
|
407
|
+
|
|
408
|
+
### Dependencies
|
|
409
|
+
|
|
410
|
+
```kotlin
|
|
411
|
+
// build.gradle.kts — replace or add to starters
|
|
412
|
+
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
|
413
|
+
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
|
|
414
|
+
runtimeOnly("org.postgresql:r2dbc-postgresql")
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Main application
|
|
418
|
+
|
|
419
|
+
Use `Netty` as the default server (Boot chooses it when `spring-boot-starter-webflux` is on the classpath and `spring-boot-starter-web` is not).
|
|
420
|
+
|
|
421
|
+
### R2DBC repositories and WebFlux controllers
|
|
422
|
+
|
|
423
|
+
Define reactive repositories (`ReactiveCrudRepository`) and inject them into `@RestController` or handler functions. Use `ServerWebExchange`, `Mono`, and `Flux` for reactive types. For **RestClient** in a reactive app, use the reactive variant and streaming; see `references/spring-framework-7.md` (Streaming Support) for alignment with Spring 7 APIs.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
**Version**: 7.0.5 (Stable) | **Java baseline**: 17 (25 recommended) | **Jakarta EE**: 11
|
|
4
4
|
|
|
5
|
+
For **reactive applications (WebFlux + R2DBC)**, combine this reference with the **Reactive stack** section in `references/spring-boot-4.md`.
|
|
6
|
+
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
## Table of Contents
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
6. [Transactional Event Listeners](#6-transactional-event-listeners)
|
|
14
14
|
7. [Module Integration Testing](#7-module-integration-testing)
|
|
15
15
|
8. [Generating Documentation](#8-generating-documentation)
|
|
16
|
+
9. [Common Pitfalls](#9-common-pitfalls)
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -218,3 +219,15 @@ void generateModuleDocumentation() throws Exception {
|
|
|
218
219
|
```
|
|
219
220
|
|
|
220
221
|
Output lands in `target/spring-modulith-docs/` (Maven) or `build/spring-modulith-docs/` (Gradle).
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 9. Common Pitfalls
|
|
226
|
+
|
|
227
|
+
| Pitfall | Remedy |
|
|
228
|
+
|--------|--------|
|
|
229
|
+
| **Circular module dependencies** | `ApplicationModules.of(...).verify()` fails. Break the cycle: introduce a shared module or move the coupling to events so no module depends on the other. |
|
|
230
|
+
| **Exposing internal types in the module API** | Public classes in the module root (e.g. `OrderService`) must not return or accept types from `internal/`. Use DTOs or domain types in the public package only. |
|
|
231
|
+
| **Forgetting the verification test in CI** | Add the module verification test (section 3) to your CI pipeline so boundary violations are caught on every commit. |
|
|
232
|
+
| **Direct service calls across modules** | One module must not inject another module's service and call it directly. Use `ApplicationEventPublisher` and `@ApplicationModuleListener` (or transactional events) for cross-module communication. |
|
|
233
|
+
| **Putting shared DTOs in one module's internal** | Types used in events or APIs consumed by several modules belong in a `shared/` (or similar) package, not in one module's `internal/`. |
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Spring Security 7 — Reference (Boot 4)
|
|
2
|
+
|
|
3
|
+
**Spring Boot**: 4.0.x | **Spring Security**: 7.0.x | **Jakarta EE**: 11
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Dependencies](#1-dependencies)
|
|
10
|
+
2. [OAuth2 Resource Server (JWT)](#2-oauth2-resource-server-jwt)
|
|
11
|
+
3. [SecurityFilterChain (Lambda DSL)](#3-securityfilterchain-lambda-dsl)
|
|
12
|
+
4. [Method Security (@PreAuthorize)](#4-method-security-preauthorize)
|
|
13
|
+
5. [CORS](#5-cors)
|
|
14
|
+
6. [application.yaml](#6-applicationyaml)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Dependencies
|
|
19
|
+
|
|
20
|
+
Spring Boot 4 BOM brings Spring Security 7. Add only what you need:
|
|
21
|
+
|
|
22
|
+
```kotlin
|
|
23
|
+
// build.gradle.kts
|
|
24
|
+
dependencies {
|
|
25
|
+
implementation("org.springframework.boot:spring-boot-starter-security")
|
|
26
|
+
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") // JWT
|
|
27
|
+
implementation("org.springframework.boot:spring-boot-starter-oauth2-client") // optional: OAuth2 login
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. OAuth2 Resource Server (JWT)
|
|
34
|
+
|
|
35
|
+
Validate JWTs from an authorization server (e.g. OIDC issuer). Lambda DSL is the only supported style in Security 7.
|
|
36
|
+
|
|
37
|
+
```java
|
|
38
|
+
import org.springframework.context.annotation.Bean;
|
|
39
|
+
import org.springframework.context.annotation.Configuration;
|
|
40
|
+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
41
|
+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
42
|
+
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|
43
|
+
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
|
44
|
+
import org.springframework.security.web.SecurityFilterChain;
|
|
45
|
+
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
46
|
+
|
|
47
|
+
@Configuration
|
|
48
|
+
@EnableWebSecurity
|
|
49
|
+
public class SecurityConfig {
|
|
50
|
+
|
|
51
|
+
@Bean
|
|
52
|
+
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
53
|
+
return http
|
|
54
|
+
.authorizeHttpRequests(auth -> auth
|
|
55
|
+
.requestMatchers("/api/public/**", "/actuator/health").permitAll()
|
|
56
|
+
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
|
57
|
+
.anyRequest().authenticated())
|
|
58
|
+
.oauth2ResourceServer(oauth2 -> oauth2
|
|
59
|
+
.jwt(jwt -> jwt.decoder(jwtDecoder())))
|
|
60
|
+
.sessionManagement(session -> session
|
|
61
|
+
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
62
|
+
.csrf(csrf -> csrf.disable()) // typical for stateless API
|
|
63
|
+
.build();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@Bean
|
|
67
|
+
JwtDecoder jwtDecoder() {
|
|
68
|
+
return NimbusJwtDecoder.withJwkSetUri("https://auth.example.com/.well-known/jwks.json").build();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
With **issuer-uri** (Boot auto-configures `JwtDecoder`):
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
# application.yaml
|
|
77
|
+
spring:
|
|
78
|
+
security:
|
|
79
|
+
oauth2:
|
|
80
|
+
resourceserver:
|
|
81
|
+
jwt:
|
|
82
|
+
issuer-uri: https://auth.example.com
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Then omit the custom `JwtDecoder` bean; Boot provides it.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 3. SecurityFilterChain (Lambda DSL)
|
|
90
|
+
|
|
91
|
+
All security configuration uses the lambda style. Example: form login + API protected by JWT.
|
|
92
|
+
|
|
93
|
+
```java
|
|
94
|
+
import org.springframework.security.config.Customizer;
|
|
95
|
+
|
|
96
|
+
@Bean
|
|
97
|
+
SecurityFilterChain webFilterChain(HttpSecurity http) throws Exception {
|
|
98
|
+
return http
|
|
99
|
+
.securityMatcher("/api/**")
|
|
100
|
+
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
|
|
101
|
+
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
|
|
102
|
+
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
103
|
+
.build();
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 4. Method Security (@PreAuthorize)
|
|
110
|
+
|
|
111
|
+
Enable method security and use SpEL in annotations (Jakarta namespace).
|
|
112
|
+
|
|
113
|
+
```java
|
|
114
|
+
@Configuration
|
|
115
|
+
@EnableMethodSecurity
|
|
116
|
+
public class MethodSecurityConfig {}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```java
|
|
120
|
+
import org.springframework.security.access.prepost.PreAuthorize;
|
|
121
|
+
|
|
122
|
+
@Service
|
|
123
|
+
public class OrderService {
|
|
124
|
+
|
|
125
|
+
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.name")
|
|
126
|
+
public Order getOrder(String userId, String orderId) {
|
|
127
|
+
return orderRepository.findById(orderId).orElseThrow();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@PreAuthorize("hasAuthority('SCOPE_orders:write')")
|
|
131
|
+
public Order create(OrderRequest request) {
|
|
132
|
+
return orderRepository.save(map(request));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Use `@PreAuthorize` / `@PostAuthorize` for read; `@PreFilter` / `@PostFilter` for filtering collections. All use Jakarta annotations in Spring Security 7.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 5. CORS
|
|
142
|
+
|
|
143
|
+
Configure CORS in the security pipeline or globally. Example: allow a frontend origin.
|
|
144
|
+
|
|
145
|
+
```java
|
|
146
|
+
import org.springframework.security.config.Customizer;
|
|
147
|
+
import org.springframework.web.cors.CorsConfiguration;
|
|
148
|
+
import org.springframework.web.cors.CorsConfigurationSource;
|
|
149
|
+
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|
150
|
+
|
|
151
|
+
@Bean
|
|
152
|
+
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
153
|
+
return http
|
|
154
|
+
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
|
155
|
+
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
|
|
156
|
+
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
|
|
157
|
+
.build();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@Bean
|
|
161
|
+
CorsConfigurationSource corsConfigurationSource() {
|
|
162
|
+
CorsConfiguration config = new CorsConfiguration();
|
|
163
|
+
config.setAllowedOrigins(List.of("https://app.example.com"));
|
|
164
|
+
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
|
165
|
+
config.setAllowedHeaders(List.of("*"));
|
|
166
|
+
config.setAllowCredentials(true);
|
|
167
|
+
|
|
168
|
+
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
169
|
+
source.registerCorsConfiguration("/**", config);
|
|
170
|
+
return source;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Or use `WebMvcConfigurer` for non-security CORS only; for APIs with credentials, the above is typical.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 6. application.yaml
|
|
179
|
+
|
|
180
|
+
Minimal Security 7 + OAuth2 RS settings:
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
spring:
|
|
184
|
+
security:
|
|
185
|
+
oauth2:
|
|
186
|
+
resourceserver:
|
|
187
|
+
jwt:
|
|
188
|
+
issuer-uri: https://auth.example.com
|
|
189
|
+
jwk-set-uri: https://auth.example.com/.well-known/jwks.json # if no issuer-uri
|
|
190
|
+
|
|
191
|
+
# Optional: restrict actuator by profile
|
|
192
|
+
management:
|
|
193
|
+
endpoints:
|
|
194
|
+
web:
|
|
195
|
+
exposure:
|
|
196
|
+
include: health,info,metrics
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
For **development only**, you can disable security (e.g. with a `SecurityFilterChain` that permits all when a profile is active). Never disable in production.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
**Summary:** Use `SecurityFilterChain` with lambda DSL, OAuth2 Resource Server with JWT for APIs, `@EnableMethodSecurity` and `@PreAuthorize` for method-level rules, and configure CORS in the security pipeline when the API is consumed by a browser client.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Troubleshooting & Migration — Spring Boot 4 / Framework 7
|
|
2
|
+
|
|
3
|
+
Quick fixes for common errors and a short checklist for migrating from Boot 3 to Boot 4.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Common errors](#1-common-errors)
|
|
10
|
+
2. [Boot 3 → 4 migration checklist](#2-boot-3--4-migration-checklist)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Common errors
|
|
15
|
+
|
|
16
|
+
### javax vs jakarta
|
|
17
|
+
|
|
18
|
+
**Symptom:** Compilation errors like `package javax.servlet does not exist`, `javax.persistence` not found, or similar for `javax.*`.
|
|
19
|
+
|
|
20
|
+
**Cause:** Spring Boot 4 and Spring Framework 7 use **Jakarta EE 11**. All `javax.*` namespaces were replaced by `jakarta.*`.
|
|
21
|
+
|
|
22
|
+
**Fix:**
|
|
23
|
+
|
|
24
|
+
- Replace imports: `javax.servlet.*` → `jakarta.servlet.*`, `javax.persistence.*` → `jakarta.persistence.*`, `javax.validation.*` → `jakarta.validation.*`, etc.
|
|
25
|
+
- Ensure dependencies use Jakarta. Spring Boot 4 BOM already brings Jakarta-based starters. Third-party libs must be Jakarta-compatible (e.g. Hibernate 7.x, Bean Validation 3.x, Servlet API 6.x).
|
|
26
|
+
- Search the project for `javax.` and replace with `jakarta.` where applicable.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### RestTemplate not found or deprecated
|
|
31
|
+
|
|
32
|
+
**Symptom:** `RestTemplate` cannot be resolved, or IDE/compiler warns it is deprecated.
|
|
33
|
+
|
|
34
|
+
**Cause:** In Spring Framework 6+, `RestTemplate` is in maintenance mode. Spring 7 promotes `RestClient` for synchronous HTTP.
|
|
35
|
+
|
|
36
|
+
**Fix:**
|
|
37
|
+
|
|
38
|
+
- Add dependency (usually already present with `spring-boot-starter-web`): `RestClient` is in `spring-web`.
|
|
39
|
+
- Replace usage:
|
|
40
|
+
|
|
41
|
+
```java
|
|
42
|
+
// Before
|
|
43
|
+
RestTemplate rest = new RestTemplate();
|
|
44
|
+
MyDto dto = rest.getForObject(url, MyDto.class);
|
|
45
|
+
|
|
46
|
+
// After (Spring 7)
|
|
47
|
+
RestClient rest = RestClient.create();
|
|
48
|
+
MyDto dto = rest.get().uri(url).retrieve().body(MyDto.class);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For declarative clients, use `HttpServiceProxyFactory` + interface. See `references/spring-framework-7.md`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### Null-safety: JSR-305 vs JSpecify
|
|
56
|
+
|
|
57
|
+
**Symptom:** Warnings or errors about `@Nullable` / `@NonNull` (e.g. wrong package or conflicting annotations).
|
|
58
|
+
|
|
59
|
+
**Cause:** Spring 7 aligns with **JSpecify** (`org.jspecify.annotations`). Legacy JSR-305 (`javax.annotation` or `org.checkerframework`) is not the standard for Spring 7.
|
|
60
|
+
|
|
61
|
+
**Fix:**
|
|
62
|
+
|
|
63
|
+
- Remove JSR-305 / Checker Framework null annotations from dependencies if possible.
|
|
64
|
+
- Add JSpecify and use it consistently:
|
|
65
|
+
|
|
66
|
+
```kotlin
|
|
67
|
+
implementation("org.jspecify:jspecify:1.0.0")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```java
|
|
71
|
+
import org.jspecify.annotations.Nullable;
|
|
72
|
+
import org.jspecify.annotations.NonNull;
|
|
73
|
+
import org.jspecify.annotations.NullMarked;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- Annotate packages or types with `@NullMarked` where you want strict null checking. Replace `javax.annotation.Nullable` with `org.jspecify.annotations.Nullable`, etc.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### Native image: reflection or classpath errors
|
|
81
|
+
|
|
82
|
+
**Symptom:** GraalVM native build fails with "Class not found", "Reflection without registration", or similar.
|
|
83
|
+
|
|
84
|
+
**Cause:** Native images need explicit metadata for reflection, resources, and dynamic proxies. Spring Boot AOT helps but not all code paths are covered.
|
|
85
|
+
|
|
86
|
+
**Fix:**
|
|
87
|
+
|
|
88
|
+
- Prefer **functional bean registration** instead of classpath scanning where possible. Use `ApplicationContextInitializer` or `BeanDefinitionRegistryPostProcessor` to register beans programmatically.
|
|
89
|
+
- For DTOs or types used in JSON/serialization, register reflection:
|
|
90
|
+
|
|
91
|
+
```java
|
|
92
|
+
@RegisterReflectionForBinding({MyDto.class, OtherDto.class})
|
|
93
|
+
@Configuration(proxyBeanMethods = false)
|
|
94
|
+
public class NativeHintsConfig {}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- Add GraalVM reachability metadata for third-party libraries if needed (e.g. `native-image.properties` or library-specific hints). Check [GraalVM Native Image documentation](https://www.graalvm.org/latest/reference-manual/native-image/) and Spring Boot’s native support.
|
|
98
|
+
- Ensure you are not loading classes only by name (e.g. `Class.forName`) without registering them for reflection.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 2. Boot 3 → 4 migration checklist
|
|
103
|
+
|
|
104
|
+
Use this as a short guide. For authoritative steps, refer to the official [Spring Boot 4 release notes](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Release-Notes) and upgrade guides.
|
|
105
|
+
|
|
106
|
+
| Step | Action |
|
|
107
|
+
|------|--------|
|
|
108
|
+
| **Java** | Use Java 17 minimum; **Java 21 or 25** recommended. |
|
|
109
|
+
| **BOM** | Update parent or BOM to Spring Boot **4.0.x** (e.g. `4.0.3`). |
|
|
110
|
+
| **javax → jakarta** | Replace all `javax.*` imports and dependencies with `jakarta.*` (servlet, persistence, validation, etc.). |
|
|
111
|
+
| **Dependencies** | Align with Boot 4: Jackson **3.x**, JPA/Hibernate **3.2 / 7.x**, Bean Validation **3.1**, Spring Framework **7.0.x**. Remove or upgrade any lib that still depends on `javax.*` or old versions. |
|
|
112
|
+
| **RestTemplate** | Migrate to **RestClient** (or WebClient for reactive). See `references/spring-framework-7.md`. |
|
|
113
|
+
| **Null annotations** | Migrate to **JSpecify** (`org.jspecify`) if you use null-safety annotations. |
|
|
114
|
+
| **Security** | Spring Security 7 uses **lambda DSL** only. Update `SecurityFilterChain` and related config to lambda style. See `references/spring-security-7.md`. |
|
|
115
|
+
| **Optional: Virtual threads** | Enable with `spring.threads.virtual.enabled: true` in `application.yaml` for eligible workloads. |
|
|
116
|
+
| **Optional: Java 25 features** | For Structured Concurrency or Scoped Values, enable `--enable-preview` in compile and run; use Boot 4 + Java 25. See `references/spring-boot-4.md`. |
|
|
117
|
+
| **Tests** | Run full test suite; fix any failures due to API changes (e.g. `RestTestClient` instead of `TestRestTemplate` where applicable). Use **Testcontainers** for integration tests if needed. See `references/spring-boot-4.md` Testing section. |
|
|
118
|
+
|
|
119
|
+
After migration, verify actuator endpoints, security rules, and database access. For deeper issues, load the appropriate reference file (e.g. `spring-security-7.md`, `spring-framework-7.md`, `spring-boot-4.md`) as indicated in the skill’s Reference Files table.
|