CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

apavithraa/springboot-architecture

Skills for creating, testing, reviewing, migrating and guarding Spring Boot 4 projects with Java 25: project scaffolding with architecture patterns, Boot 4 test templates, code review, Boot 3 to 4 migration, and a team harness of build gates and agent hooks.

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

spring-boot-4-migration.mdskills/springboot-migration/references/

Spring Boot 3 → 4 Migration

Official: 4.0 Migration Guide, 4.1 Release Notes. Checked against Boot 4.1.1 on 2026-10-17.

New Boot 4 features (RestTestClient, HTTP service clients, API versioning, native resilience, JSpecify) are covered in ../../creating-springboot-projects/references/spring-boot-4-features.md. This file covers what must change.

Contents

  1. Targets
  2. Strategy
  3. Phase 1: Dependencies
  4. Phase 2: Code
  5. Phase 3: Tests
  6. Phase 4: Configuration
  7. Upgrading from 4.0 to 4.1
  8. Verification and common failures
  9. Checklist

Targets

ComponentMinimumTarget
Java1725 (LTS). Newer releases: ../../creating-springboot-projects/references/java-version-policy.md
Spring Boot4.04.1.x
Spring Framework7.07.0.x (Boot 4.1.1 uses 7.0.9)
Jakarta EE / Servlet11 / 6.1same
Spring Modulith2.02.1.x (spring-modulith-2-migration.md)
Testcontainers2.02.0.x (Boot 4.1.1 manages 2.0.5; testcontainers-2-migration.md)

Go from 3.x straight to 4.1. Clear 4.0 deprecations on the way: 4.1 removes everything deprecated in 4.0.

Strategy

OptionHowUse when
Classic startersReplace starters with spring-boot-starter-classic and spring-boot-starter-test-classicLarge apps; you want the build green first. They provide all modules but exclude their transitive dependencies
DirectMove to modular starters now (web → webmvc, and so on)Small or medium apps

Spring recommends moving off the classic starters eventually.


Phase 1: Dependencies

ChangeBeforeAfter
Web MVC starterspring-boot-starter-web (deprecated)spring-boot-starter-webmvc
AOP starterspring-boot-starter-aopspring-boot-starter-aspectj, only if the app uses AspectJ (@Aspect from org.aspectj.lang.annotation, Micrometer @Timed/@Counted/@Observed, Resilience4j annotations). Otherwise remove it
RestClient / RestTemplateincluded in the web starteradd spring-boot-starter-restclient
WebClientincluded in webfluxadd spring-boot-starter-webclient
Flyway / Liquibaseflyway-core / liquibase-core alonespring-boot-starter-flyway (+ flyway-database-<db>) / spring-boot-starter-liquibase
Security testsspring-security-testspring-boot-starter-security-test (needed for @WithMockUser / @WithUserDetails)
Modular test startersspring-boot-starter-test covered everythingadd spring-boot-starter-<module>-test for slices you use (for example -webmvc-test, -data-jpa-test), or use -test-classic
Spring Retryspring-retry + @EnableRetryremove; use native resilience (Phase 2)
Jackson 2com.fasterxml.jackson.core:jackson-databindtools.jackson.core:jackson-databind (Phase 2). Temporary bridge: spring-boot-jackson2 (deprecated)

@Async, @Transactional, @Cacheable, and native @Retryable/@ConcurrencyLimit use Spring AOP proxies. They do not need the AspectJ starter.


Phase 2: Code

Jackson 3

Group ID and packages change for jackson-core and jackson-databind only. jackson-annotations keeps com.fasterxml.jackson.core and the com.fasterxml.jackson.annotation package on purpose.

Jackson 2 / Boot 3Jackson 3 / Boot 4
com.fasterxml.jackson.databind.*, com.fasterxml.jackson.core.*tools.jackson.databind.*, tools.jackson.core.*
ObjectMapper bean customizationJsonMapper (tools.jackson.databind.json.JsonMapper)
JsonProcessingException (checked)JacksonException (unchecked). Remove throws/catch that only existed for it
JsonSerializer / JsonDeserializer / SerializerProviderValueSerializer / ValueDeserializer / SerializationContext
Jackson2ObjectMapperBuilderCustomizerJsonMapperBuilderCustomizer (org.springframework.boot.jackson.autoconfigure)
@JsonComponent / @JsonMixin@JacksonComponent / @JacksonMixin
JsonObjectSerializer / JsonValueDeserializerObjectValueSerializer / ObjectValueDeserializer
builder.serializationInclusion(...)builder.changeDefaultPropertyInclusion(incl -> incl.withValueInclusion(...))
@Component
class JacksonConfig implements JsonMapperBuilderCustomizer {
    public void customize(JsonMapper.Builder builder) {
        builder.changeDefaultPropertyInclusion(
            incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL));
    }
}

Libraries that bring their own Jackson 2 serializers (some Redis, Kafka, or HTTP client setups) need their Jackson 3 variants. For Spring Data Redis 4, see ../../code-reviewer/references/performance-patterns.md#distributed-caching-redis.

Package relocations

OldNew
org.springframework.boot.BootstrapRegistry / BootstrapContextorg.springframework.boot.bootstrap.*
org.springframework.boot.autoconfigure.domain.EntityScanorg.springframework.boot.persistence.autoconfigure.EntityScan
org.springframework.boot.test.autoconfigure.web.servlet.* (@WebMvcTest, @AutoConfigureMockMvc)org.springframework.boot.webmvc.test.autoconfigure.*

Spring Retry → native resilience

  1. Remove spring-retry.
  2. Replace @EnableRetry with @EnableResilientMethods on a @Configuration class. It is required; Boot does not auto-enable it.
  3. Imports: org.springframework.retry.annotation.* → org.springframework.resilience.annotation.*.
  4. Parameters: retryFor → includes; backoff = @Backoff(delay = 1000, multiplier = 2) → delay = 1000, multiplier = 2; maxAttempts (total calls) → maxRetries (retries after the first call): maxAttempts = 4 becomes maxRetries = 3.
  5. @Recover has no native equivalent. Catch the final exception in the caller, or use RetryTemplate.
  6. Circuit breakers stay on Resilience4j (resilience4j-spring-boot4, needs the AspectJ starter).

Optional modernization

Not required for the upgrade. Do it after the build is green:

  • Manual HttpServiceProxyFactory beans → @ImportHttpServices; configure groups with spring.http.serviceclient.<group>.base-url and shared settings with spring.http.clients.*.
  • Custom API-versioning filters → spring.mvc.apiversion.* and version = "..." on mappings.

Details: ../../creating-springboot-projects/references/spring-boot-4-features.md.


Phase 3: Tests

ChangeFix
@MockBean / @SpyBean were removed in 4.0 (deprecated since 3.4)@MockitoBean / @MockitoSpyBean from org.springframework.test.context.bean.override.mockito
@MockBean fields inside a @TestConfiguration classNot supported by @MockitoBean. Move them to the test class, or to a type-level annotation: @MockitoBean(types = UserRepository.class) (repeatable; works on the test class, a superclass, or a meta-annotation)
@SpringBootTest no longer provides MockMvcAdd @AutoConfigureMockMvc
@SpringBootTest no longer provides TestRestTemplateAdd @AutoConfigureTestRestTemplate, or move to RestTestClient with @AutoConfigureRestTestClient. TestRestTemplate is not deprecated
@WithMockUser / @WithUserDetails stop workingAdd spring-boot-starter-security-test

@AutoConfigureWebTestClient is for the reactive WebTestClient. It does not replace TestRestTemplate.

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class UserControllerTest {
    @Autowired RestTestClient client;

    @Test
    void getsUser() {
        client.get().uri("/users/1").exchange()
              .expectStatus().isOk()
              .expectBody(User.class);
    }
}

Phase 4: Configuration

ChangeAction
Liveness and readiness probes are on by defaultExpect /actuator/health/liveness and /readiness. Disable with management.endpoint.health.probes.enabled=false
DevTools live reload is off by defaultspring.devtools.livereload.enabled=true to turn it on
Jackson properties4.0 moved JSON-specific spring.jackson.read.*/write.* to spring.jackson.json.read.*/json.write.*, and replaced spring.jackson.parser.* with json.read.*. In 4.1, spring.jackson.read.*/write.* exist again for stream features (StreamReadFeature/StreamWriteFeature)

Jackson property families in 4.1:

FamilyFeature enumExample
spring.jackson.json.read.* / json.write.*JsonReadFeature / JsonWriteFeaturespring.jackson.json.read.allow-trailing-comma=true
spring.jackson.serialization.* / deserialization.*SerializationFeature / DeserializationFeaturespring.jackson.serialization.indent-output=true (not json.write)
spring.jackson.read.* / write.*StreamReadFeature / StreamWriteFeatureformat-independent stream settings

Run the app once with spring-boot-properties-migrator on the classpath. It reports renamed properties at startup. Remove it afterwards.


Upgrading from 4.0 to 4.1

  • Items deprecated in 4.0 are removed.
  • spring.data.jpa.repositories.bootstrap-mode=deferred now fails at startup if no suitable AsyncTaskExecutor bean exists. With lazy, the auto-configured bootstrap executor is no longer set.
  • jOOQ 3.20 is the minimum, and it requires Java 21.
  • The Maven plugin no longer skips test AOT processing on -DskipTests. Use -Dmaven.test.skip=true.
  • The layertools jar mode is removed. Use -Djarmode=tools.
  • Tomcat's temporary base directory is deleted on shutdown. Set server.tomcat.basedir if you need it to persist.
  • Derby is deprecated. Move to H2 or HSQLDB.

Verification and common failures

After each phase: ./mvnw clean verify (or ./gradlew build), start the app, and check /actuator/health.

SymptomLikely causeFix
NoClassDefFoundError / NoSuchMethodError for com.fasterxml.jackson.databind.*A library still needs Jackson 2./mvnw dependency:tree -Dincludes=com.fasterxml.jackson.core; upgrade the library or add spring-boot-jackson2 temporarily
RestClient.Builder bean not foundMissing spring-boot-starter-restclientAdd it
Flyway migrations do not runOnly flyway-core on the classpathAdd spring-boot-starter-flyway
@Retryable / @ConcurrencyLimit do nothingMissing @EnableResilientMethods, old org.springframework.retry imports, or a self-invocation (call from the same class bypasses the proxy)Fix the enablement, imports, or call path
MockMvc / TestRestTemplate bean not found in testsNo longer auto-provided@AutoConfigureMockMvc / @AutoConfigureTestRestTemplate
@WithMockUser ignoredMissing security test starterAdd spring-boot-starter-security-test

Checklist

Phase 1: Dependencies

  • Boot 4.1.x; webmvc, restclient/webclient, flyway/liquibase starters
  • AspectJ starter kept only for real AspectJ use
  • Module test starters (or -test-classic); spring-boot-starter-security-test
  • spring-retry removed; Jackson 3 coordinates; Testcontainers 2 coordinates

Phase 2: Code

  • Jackson 3 imports, classes, customizers
  • Package relocations (EntityScan, BootstrapRegistry, WebMvcTest)
  • Native resilience with @EnableResilientMethods

Phase 3: Tests

  • @MockitoBean / @MockitoSpyBean; no mocks in @TestConfiguration
  • @AutoConfigureMockMvc / @AutoConfigureTestRestTemplate or RestTestClient

Phase 4: Configuration

  • Properties migrated (spring-boot-properties-migrator run once)
  • Health probes and DevTools defaults reviewed

References

tile.json