Skip to main content

spring-boot-engineer

Use when building, modifying, or reviewing Spring Boot 4.x applications (Spring Framework 7, Spring Security 7, Hibernate 7, Jackson 3) in Java or Kotlin — REST controllers, Spring Data JPA repositories, OAuth2 / JWT, WebFlux reactive endpoints, Kafka / event-driven code, Resilience4j, Spring Cloud, or Spring Boot tests. Covers common pitfalls that break in production: @Transactional self-invocation, N+1 queries, Kotlin + JPA plugins, blocking calls inside WebFlux. Migrating from Boot 3.x? See Setup Check — major breaking changes: Jackson 3 package rename, @MockBean removed, and() in Security DSL removed, Undertow dropped.

Source facts

Repository
JetBrains/junie-extensions
Last source activity
April 27, 2026 at 08:24
Detected SKILL.md language
English
Stars
23
Forks
6

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
12 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
spring-boot-engineer
description
Use when building, modifying, or reviewing Spring Boot 4.x applications (Spring Framework 7, Spring Security 7, Hibernate 7, Jackson 3) in Java or Kotlin — REST controllers, Spring Data JPA repositories, OAuth2 / JWT, WebFlux reactive endpoints, Kafka / event-driven code, Resilience4j, Spring Cloud, or Spring Boot tests. Covers common pitfalls that break in production: @Transactional self-invocation, N+1 queries, Kotlin + JPA plugins, blocking calls inside WebFlux. Migrating from Boot 3.x? See Setup Check — major breaking changes: Jackson 3 package rename, @MockBean removed, and() in Security DSL removed, Undertow dropped.
# Spring Boot Engineer ## Core Workflow 1. **Setup check** — run Setup Check below before writing any code. 2. **Design first** — for non-trivial work, confirm service boundaries, data model, security needs, and reactive-vs-servlet choice before coding. 3. **Implement bottom-up** — entity → repository → service → controller. Constructor injection only. Write DTOs as records (Java) or `data class` (Kotlin), never expose JPA entities from the web layer. 4. **Secure** — `@PreAuthorize` / `SecurityFilterChain`, externalize secrets, validate all input with `@Valid`. 5. **Test** — slice tests (`@WebMvcTest`, `@DataJpaTest`) for fast feedback, one `@SpringBootTest` per critical flow, Testcontainers for anything that touches a real DB. 6. **Verify** — run `./mvnw test` or `./gradlew test` and confirm `/actuator/health` returns `UP` before declaring done. ## Setup Check **Mandatory before any code change.** ### Step 1 — Is this actually a Spring Boot project? Look for one of these, in this order: - `spring-boot-starter-parent` or `spring-boot-dependencies` in `pom.xml`. - `org.springframework.boot` plugin in `build.gradle` / `build.gradle.kts`. - A class annotated with `@SpringBootApplication`. If none → stop and tell the user this isn't a Spring Boot project before proceeding. ### Step 2 — Kotlin project? Verify required compiler plugins. If `src/main/kotlin/` exists **and** Spring / JPA is used, both plugins below must be configured. Without them Spring proxies and JPA entities fail at runtime with cryptic errors: | Plugin | Why it's needed | |---|---| | `kotlin("plugin.spring")` (`kotlin-spring`) | Opens classes annotated with `@Component` / `@Service` / `@Configuration` / `@Transactional` / `@Async` / `@Cacheable` / `@SpringBootTest` — CGLIB proxies cannot subclass `final` classes. | | `kotlin("plugin.jpa")` (`kotlin-jpa`) | Generates a no-arg constructor for `@Entity` / `@Embeddable` / `@MappedSuperclass`. Required for JPA to instantiate entities via reflection. | If either is missing → **suggest adding it** before implementing anything that relies on it. ```kotlin plugins { kotlin("plugin.spring") version "<kotlin-version>" kotlin("plugin.jpa") version "<kotlin-version>" } ``` Also confirm `kotlin-reflect` is on the classpath (included by `spring-boot-starter`). ### Step 3 — Java version & runtime Spring Boot 4.x requires **Java 17+** (Java 21+ recommended — first-class virtual thread support). Check `<java.version>` (Maven) or `java.toolchain` / `sourceCompatibility` (Gradle). Virtual threads: enable via `spring.threads.virtual.enabled=true`. Don't use them unconditionally — harmful with `synchronized` blocks and `ThreadLocal`-heavy libraries. **Undertow is no longer supported** in Boot 4 (dropped Servlet 6.1 compatibility). Use Tomcat (default) or Jetty. ### Step 4 — Jackson version Spring Boot 4 defaults to **Jackson 3**. Most packages were renamed: `com.fasterxml.jackson` → `tools.jackson`. Exception: `jackson-annotations` intentionally keeps the old namespace (`com.fasterxml.jackson.annotation`) for backward compatibility. Any code importing `jackson-databind` or `jackson-core` classes directly will break — update imports. No official compatibility bridge exists; migration must be done manually. If the project already uses Jackson 3 → proceed. If still on Jackson 2 → flag the migration before adding new Jackson-dependent code. ## Reference Guide Load on demand — don't read all of these upfront. | Topic | Reference | Load when | |-------|-----------|-----------| | Web Layer | `references/web.md` | Controllers, DTO boundary, validation, `ProblemDetail`, pagination, CORS, deprecations | | Data Access | `references/data.md` | JPA / Hibernate pitfalls: N+1, `open-in-view`, `@Transactional` self-invocation, fetch-join + pagination, Hikari tuning | | Security | `references/security.md` | Spring Security 7 `SecurityFilterChain`, CSRF rules, JWT resource server, method security, `/actuator/*` hardening | | Testing | `references/testing.md` | Test slices (`@WebMvcTest` / `@DataJpaTest` / `@RestClientTest`), `@MockitoBean` migration, Testcontainers + `@ServiceConnection` | | Migrations | `references/migrations.md` | Flyway / Liquibase, zero-downtime schema change (expand-contract), baseline-on-migrate, `CREATE INDEX CONCURRENTLY` | | Scheduling & Observability | `references/scheduling-observability.md` | `@Scheduled` in a cluster (ShedLock), Actuator exposure, health probes, Micrometer cardinality, virtual threads trade-offs | | Kotlin | `references/kotlin.md` | `kotlin-spring` / `kotlin-jpa` plugins, `@field:` validation, `suspend` controllers, `data class` vs `@Entity` | | Event-Driven | `references/event-driven.md` | `@TransactionalEventListener`, `@Async` traps, Kafka idempotence, outbox pattern | | Resilience | `references/resilience.md` | Resilience4j annotation order, `fallbackMethod` rules, breaker + retry interaction, distributed vs local rate-limit | | Reactive (WebFlux) | `references/reactive.md` | When WebFlux is the right choice, `.block()` traps, `Schedulers.boundedElastic()`, context propagation, backpressure | | Cloud Native | `references/cloud.md` | `spring.config.import` (not `bootstrap.yml`), `@RefreshScope` limits, Gateway on WebFlux, k8s vs Spring Cloud choice | ## Constraints ### MUST DO | Rule | Correct pattern | |------|-----------------| | Constructor injection | `public MyService(Dep dep) { this.dep = dep; }` — never `@Autowired` on a field | | Validate every mutating endpoint | `@Valid @RequestBody MyRequest req` + Bean Validation annotations on the DTO | | DTOs at the web boundary | Java `record` or Kotlin `data class` — **never** return or accept JPA entities directly | | Type-safe config | `@ConfigurationProperties(prefix = "app")` bound to a record/class, not `@Value("${…}")` scattered across the codebase | | Correct stereotype | `@Service` for business logic, `@Repository` for data, `@RestController` for HTTP, `@Component` only when nothing else fits | | Transaction scope | `@Transactional` only on `public` methods of a Spring-managed bean, called from outside the class (see MUST NOT below) | | Read-only hint | `@Transactional(readOnly = true)` on queries — lets Hibernate skip dirty-checking | | Rollback on checked exceptions | `@Transactional(rollbackFor = Exception.class)` when the method throws checked exceptions you want to roll back | | Global error handling | `@RestControllerAdvice` + `ProblemDetail` (RFC 7807) — never leak stack traces to clients | | Externalize secrets | Env vars or Spring Cloud Config — never commit secrets to `application.properties` / `application.yml` | | Kotlin + Spring | `kotlin("plugin.spring")` always; `kotlin("plugin.jpa")` when JPA is used | | Kotlin validation | `@field:NotBlank` on `data class` properties — bare `@NotBlank` is silently ignored | | Post-commit side effects | `@TransactionalEventListener(phase = AFTER_COMMIT)` for email / Kafka / external calls — never inline after a `save()` inside the same transaction | ### MUST NOT — `@Transactional` pitfalls that break in production - **Self-invocation.** Calling `this.methodWithTransactional()` from another method in the same bean bypasses the proxy — no transaction starts. If you need it, inject `self` (`@Lazy @Autowired MyService self`) or extract the method to a separate bean. - **Private / package-private / `final` methods.** Proxies cannot intercept them. `@Transactional` must be on `public` non-`final` methods. (In Kotlin: add `kotlin-spring` plugin so classes/methods are open.) - **Checked exceptions without `rollbackFor`.** By default Spring rolls back only on `RuntimeException` / `Error`. Declare `@Transactional(rollbackFor = IOException.class)` (or a common superclass) when you want checked exceptions to roll back. - **`@Async` + `@Transactional` on the same method.** The async thread doesn't inherit the transaction context — entity becomes detached, you get `LazyInitializationException` or no transaction at all. Split into two beans or use `@TransactionalEventListener(phase = AFTER_COMMIT)`. - **Writes inside `readOnly = true`.** Hibernate may skip the flush — your update silently disappears. - **`@Transactional` on a `@PostConstruct` method.** Proxy isn't fully initialized yet; the annotation has no effect. ### MUST NOT — general - Field injection (`@Autowired` on fields) — breaks testability and hides required dependencies. - Skipping `@Valid` on API input — request bodies reach your service with whatever the client sent. - Using `@Component` when a more specific stereotype fits. - Mixing blocking and reactive code: no `.block()` / `.toFuture().get()` inside a `Mono` / `Flux` chain; no blocking JDBC inside a WebFlux controller. Wrap unavoidable blocking calls with `Mono.fromCallable(...).subscribeOn(Schedulers.boundedElastic())`. - Storing secrets, connection strings or tokens in `application.properties` / `application.yml` committed to git. - Hardcoding URLs / environment-specific values — use profiles (`application-dev.yml`, `application-prod.yml`) and env vars. - Removed Boot 3.x deprecated APIs — all of these are gone in Boot 4 and will fail to compile: - `WebSecurityConfigurerAdapter` (use `SecurityFilterChain` bean) - `antMatchers(...)` (use `requestMatchers(...)`) - `WebMvcConfigurerAdapter` (implement `WebMvcConfigurer`) - `and()` in `HttpSecurity` DSL (use separate lambda calls) - `@MockBean` / `@SpyBean` (use `@MockitoBean` / `@MockitoSpyBean`) - `authorizeRequests()` (use `authorizeHttpRequests()`) - **Jackson 3 imports**: `com.fasterxml.jackson.*` → `tools.jackson.*`. Don't write new code against Jackson 2 packages on a Boot 4 project. - Undertow embedded server — not supported. Don't add `spring-boot-starter-undertow`. - Returning or accepting JPA entities at the controller layer — leaks persistence details, causes lazy-loading blowups (`could not initialize proxy — no Session`), breaks API contracts on entity refactors. - N+1 queries: `repository.findAll()` followed by accessing `@OneToMany` lazy associations in a loop. Use `@EntityGraph`, `JOIN FETCH`, or projections. See `references/data.md`. - `spring.jpa.open-in-view=true` in production (the Spring Boot default!). Explicitly set it to `false` — OSIV hides lazy-loading bugs and holds the DB connection for the entire HTTP request. ## Output Format When implementing a new feature, deliver in this order: 1. Migration (Flyway / Liquibase) if schema changes are needed. 2. Entity + Repository. 3. Service with `@Transactional` boundaries. 4. DTOs (request + response) as records / data classes. 5. Controller + `@RestControllerAdvice` entries for new exception types. 6. Tests: one `@DataJpaTest` for repository custom queries, one `@WebMvcTest` per controller, one `@SpringBootTest` for the full happy path. 7. One-line summary of the key architectural decisions (why this transaction boundary, why this projection, why this status code).
View on GitHub