Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ buildscript {

plugins {
id "java"
id "org.springframework.boot" version "3.5.6"
id "org.springframework.boot" version "4.0.1"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Spring Boot 4.0.1 release date official

💡 Result:

Spring Boot 4.0.1 was officially released on December 18, 2025. [1][2]

Sources:
[1] Spring blog announcement — "Spring Boot 4.0.1 available now" (Dec 18, 2025).
[2] Maven Central / Spring Boot artifacts showing 4.0.1 published (Dec 18, 2025).


🌐 Web query:

Spring Boot 4.0 vs 3.5 breaking changes migration guide

💡 Result:

Below is a concise migration checklist and the main breaking-change areas when moving from Spring Boot 3.5 → 4.0, with links to the official migration material and detailed topics to review.

Quick actions (order)

  1. Upgrade to latest 3.5.x and run tests. [2]
  2. Update JDK to supported baseline (Java 17 minimum; Java 21/25 supported). [1][2]
  3. Read the full 4.0 migration guide and release notes, then migrate incrementally (branch + CI). [2][1]

High‑impact breaking changes to review and fix

  • Spring Framework / platform baseline

    • Spring Framework 7 / platform upgrades — check removed deprecated APIs your app uses. [2][1]
  • Jackson 2 → Jackson 3 (major migration)

    • Boot 4 defaults to Jackson 3 (new groupId/package changes: com.fasterxml.jackson → tools.jackson; jackson‑annotations exception). Many classes/props renamed; Jackson 2 support is available temporarily via a compatibility module but deprecated. Use Spring’s Jackson migration docs and OpenRewrite recipes to automate refactors. Test serialization/deserialization thoroughly. [3][2][4]
  • Configuration/property changes

    • Several property names reorganized (e.g., some spring.jackson properties moved under different paths); consult the configuration changelog in the migration guide. [2][4]
  • Build tool / dependency minimums

    • Gradle 8.x (8.14+) or 9.x recommended; updated dependency management for core libs. Verify plugin compatibility. [2][4]
  • Kotlin / language support

    • Kotlin 2.2 support noted (if you use Kotlin, update and test). [8] (migration guide)
  • Micrometer / tracing changes

    • spring-boot-micrometer-tracing modularization (separate Brave / OpenTelemetry modules) and property renames — update dependencies and config. [6]
  • Actuator / endpoint / annotation changes

    • Some annotations (nullable/non-null) handling and actuator parameter annotation behavior changed; migrate to recommended JSpecify/org.jspecify annotations or OptionalParameter where applicable. [0][2]
  • Static resources / security defaults

    • Added common static location for fonts (/fonts/**) — may affect security rules; exclude if undesired. [5]
  • Third‑party ecosystem impacts

    • Spring Data, Spring Security and some Spring projects now target Jackson 3; some ecosystem projects may still require Jackson 2 — review your transitive deps and libraries (Spring Data REST requires Jackson 3). [3][2]

How to proceed (practical)

  • Run dependency analysis (mvn dependency:tree or Gradle deps). Replace com.fasterxml.jackson artifacts with tools.jackson where needed. [3]
  • Use OpenRewrite automated recipes (UpgradeJackson_2_3 etc.) and Spring Application Advisor for code suggestions. [3]
  • Add temporary spring-boot-jackson2 if blocked by libraries (deprecated, short‑term fix). [2]
  • Create a migration branch, compile, fix API/import errors, run integration tests, verify JSON contracts and security endpoints. [2][3][4]

Essential reading (start here)

  • Spring Blog: Spring Boot 4.0.0 announcement / overview. [1]
  • Spring Boot 4.0 Migration Guide (official, exhaustive list + config changelog). [2]
  • Spring blog: Introducing Jackson 3 support in Spring (Jackson 3 migration details). [3]
  • Spring Boot 4.0 release/RC notes (breaking changes & module notes). [4]

If you want, I can:

  • Generate a targeted checklist for your project (scan pom/gradle + source) and list exact imports/classes to change, or
  • Run an automated OpenRewrite recipe plan you can apply. Which would you prefer?

Sources
[1] Spring blog — “Spring Boot 4.0.0 available now”.
[2] Spring Boot 4.0 Migration Guide / Release Notes (spring-projects/spring-boot wiki).
[3] Spring blog — “Introducing Jackson 3 support in Spring” (Jackson 3 migration details).
[4] Spring Boot 4.0 Release & RC notes (GitHub wiki).


🌐 Web query:

Spring Boot version history 3.5.6 4.0.1

💡 Result:

  • Spring Boot 3.5.6 — released Sep 18, 2025; maintenance release with ~43 bug fixes, docs improvements and dependency upgrades; available from Maven Central. [1]

  • Spring Boot 4.0.1 — released Dec 18, 2025; maintenance/patch release with ~88 bug fixes, documentation improvements and dependency upgrades; available from Maven Central. [2]

Sources:
[1] Spring blog — "Spring Boot 3.5.6 available now" (Sep 18, 2025).
[2] Spring blog — "Spring Boot 4.0.1 available now" (Dec 18, 2025).


Review migration guide and address breaking changes for Spring Boot 4.0.1 upgrade.

Spring Boot 4.0.1 is officially released (December 2025). This major version upgrade from 3.5.6 introduces several breaking changes that must be addressed:

  • Jackson 2 → 3 migration: GroupId changes from com.fasterxml.jackson to tools.jackson and package restructuring. Ensure all Jackson dependencies are updated and serialization/deserialization thoroughly tested.
  • Java 17 minimum: Update baseline JDK requirement; Java 21/25 are supported.
  • Spring Framework 7: Review for removed deprecated APIs your application uses.
  • Gradle 8.14+ or 9.x: Update build tool version if not already met.
  • Configuration changes: Spring Jackson properties have been reorganized; consult the official migration guide.
  • Micrometer/tracing modularization: Separate Brave/OpenTelemetry modules with property renames.
  • Third-party ecosystem: Some Spring projects now require Jackson 3; verify transitive dependencies.

Use OpenRewrite recipes for automated Jackson migration and the official Spring Boot 4.0 Migration Guide for exhaustive breaking changes. Test thoroughly, including JSON contracts and security endpoints.

id "idea"
id "com.adarshr.test-logger" version "4.0.0"
}
Expand All @@ -28,7 +28,6 @@ jar.enabled = false

repositories {
mavenCentral()
maven { url "https://jitpack.io" }
}

compileJava.dependsOn(processResources)
Expand Down Expand Up @@ -143,9 +142,13 @@ dependencies {
implementation("org.checkerframework:checker-qual:3.51.0")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-webmvc")
implementation("org.springframework.boot:spring-boot-starter-jackson")
implementation("org.springframework.boot:spring-boot-jackson2")
implementation("org.springframework.boot:spring-boot-starter-restclient")
implementation("org.springframework.boot:spring-boot-starter-amqp")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.security:spring-security-access")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("org.springframework.boot:spring-boot-starter-mail")
implementation("org.springframework.boot:spring-boot-starter-validation")
Expand All @@ -154,6 +157,8 @@ dependencies {
implementation("com.github.ben-manes.caffeine:caffeine")

testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
testImplementation("org.springframework.boot:spring-boot-starter-security-test")
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
testImplementation("org.springframework.security:spring-security-test")
testImplementation("com.jayway.jsonpath:json-path")
Expand All @@ -165,14 +170,16 @@ dependencies {
// Manually managed dependencies
def elideVersion = "7.1.15"
def springdocVersion = "2.8.13"
def commonsVersion = "20251112-0a26247"
implementation("com.yahoo.elide:elide-core:${elideVersion}")
implementation("com.yahoo.elide:elide-model-config:${elideVersion}")
implementation("com.yahoo.elide:elide-spring-boot-autoconfigure:${elideVersion}")
implementation("com.yahoo.elide:elide-swagger:${elideVersion}")
implementation("com.yahoo.elide:elide-datastore-jpa:${elideVersion}")
implementation("com.yahoo.elide:elide-datastore-multiplex:${elideVersion}")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:${springdocVersion}")
implementation("com.github.FAForever:faf-java-commons:0e5d22ffff6e4dea81bac494d532627fcca8ebc4")
implementation("com.faforever.commons:data:${commonsVersion}")
implementation("com.faforever.commons:api:${commonsVersion}")
implementation("org.kohsuke:github-api:1.330")
implementation("org.eclipse.jgit:org.eclipse.jgit:7.3.0.202506031305-r")
implementation("org.jetbrains:annotations:26.0.2-1")
Expand Down
14 changes: 7 additions & 7 deletions src/inttest/java/com/faforever/api/clan/ClanControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
import com.faforever.api.player.PlayerRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.Sql.ExecutionPhase;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import static org.hamcrest.Matchers.is;
Expand Down Expand Up @@ -78,7 +78,7 @@ public void createClanWithSuccess() throws Exception {
assertNull(player.getClan());
assertFalse(clanRepository.findOneByName(NEW_CLAN_NAME).isPresent());

MultiValueMap<String, String> params = new HttpHeaders();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", NEW_CLAN_NAME);
params.add("tag", NEW_CLAN_TAG);
params.add("description", NEW_CLAN_DESCRIPTION);
Expand All @@ -98,15 +98,15 @@ public void createClanWithSuccess() throws Exception {

@Test
public void createClanWithoutAuth() throws Exception {
MultiValueMap<String, String> params = new HttpHeaders();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", NEW_CLAN_NAME);
params.add("tag", NEW_CLAN_TAG);
params.add("description", NEW_CLAN_DESCRIPTION);

mockMvc.perform(
post("/clans/create")
.params(params))
.andExpect(status().isForbidden());
.andExpect(status().isUnauthorized());
}

@Test
Expand All @@ -116,7 +116,7 @@ public void createClanWithExistingName() throws Exception {
assertNull(player.getClan());
assertTrue(clanRepository.findOneByName(EXISTING_CLAN).isPresent());

MultiValueMap<String, String> params = new HttpHeaders();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", EXISTING_CLAN);
params.add("tag", NEW_CLAN_TAG);
params.add("description", NEW_CLAN_DESCRIPTION);
Expand All @@ -138,7 +138,7 @@ public void createClanWithExistingTag() throws Exception {
assertNull(player.getClan());
assertFalse(clanRepository.findOneByName(NEW_CLAN_NAME).isPresent());

MultiValueMap<String, String> params = new HttpHeaders();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", NEW_CLAN_NAME);
params.add("tag", "123");
params.add("description", NEW_CLAN_DESCRIPTION);
Expand All @@ -160,7 +160,7 @@ public void createSecondClan() throws Exception {
assertNotNull(player.getClan());
assertFalse(clanRepository.findOneByName(NEW_CLAN_NAME).isPresent());

MultiValueMap<String, String> params = new HttpHeaders();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", NEW_CLAN_NAME);
params.add("tag", NEW_CLAN_TAG);
params.add("description", NEW_CLAN_DESCRIPTION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.testcontainers.containers.GenericContainer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public void anonymousUserCannotCreateValidModerationReport() throws Exception {
post("/data/moderationReport")
.header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE)
.content(createJsonApiContent(validModerationReport)))
.andExpect(status().isForbidden());
.andExpect(status().isUnauthorized());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class MeControllerTest extends AbstractIntegrationTest {
@Test
public void withoutTokenUnauthorized() throws Exception {
mockMvc.perform(get("/me"))
.andExpect(status().isForbidden());
.andExpect(status().isUnauthorized());
}

@Test
Expand Down
Loading
Loading