
You upgrade your JDK — maybe from Java 8 to 17, or 11 to 21 — and suddenly your previously rock-solid Spring Boot application refuses to start. The frustrating part isn’t that it’s broken; it’s that the error messages are often vague, indirect, or buried inside a stack trace that points to a symptom rather than the real cause.
What this typically looks like:
- The build fails outright, or builds successfully but the app crashes on startup
- Errors like
UnsupportedClassVersionError,NoSuchMethodError, orIllegalAccessError - Sometimes no error at all — the app exits immediately after printing the banner
- Code that worked fine yesterday now fails, with zero changes made
This is a classic “it’s not your code, it’s your environment” problem — and it’s extremely common after any Java LTS upgrade (8→11, 11→17, 17→21).
Common Reasons Spring Boot Fails After a Java Upgrade
1. Java Version Mismatch Between Build and Runtime
Your IDE compiles with Java 17, but your JAVA_HOME or terminal still points to Java 11 when you run the jar. This mismatch causes UnsupportedClassVersionError immediately on startup.
2. Spring Boot Version Incompatibility
Older Spring Boot versions (2.x, particularly before 2.5) have limited or no support for newer Java versions. Spring Boot 3.x requires Java 17 as a minimum. If you upgraded your JDK but you’re still on Spring Boot 2.7, you may hit subtle incompatibilities, especially in reflection-heavy libraries like Hibernate and Jackson.
3. Maven / Gradle Compiler Plugin Still Targeting the Old Version
Even after installing a new JDK, your build configuration might still explicitly target the old Java version — creating a mismatch between what gets compiled and what the runtime expects.
4. Deprecated or Removed JVM Options
JVM flags that worked fine in Java 8 — especially PermGen/Metaspace settings or certain --add-opens module flags — are either removed or behave differently in newer runtimes and can cause immediate startup failures.
How to Fix It — Step by Step
Step 1: Update Java Version in pom.xml
Open your pom.xml and check the <properties> block:
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
If you have an explicit maven-compiler-plugin entry, update that too:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
For Gradle (build.gradle):
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
Step 2: Update the Spring Boot Parent Version
If you’ve moved to Java 17+, update your Spring Boot parent to 3.x:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
⚠️ Important — javax to jakarta namespace migration: Spring Boot 3.x migrates from javax.* to jakarta.*. Every import using the old namespace must be updated:
// Before — Spring Boot 2.x (Java 8 / 11)
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
// After — Spring Boot 3.x (Java 17+)
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
This is the single biggest source of “it builds cleanly but throws weird errors at runtime” issues during a 2.x → 3.x migration.
Step 3: Verify Build and Runtime Are on the Same JDK
In your terminal, confirm what Java version is actually being used:
java -version
javac -version
And check JAVA_HOME:
# Linux / macOS
echo $JAVA_HOME
# Windows
echo %JAVA_HOME%
If your IDE shows Java 17 but the terminal resolves to Java 11, that mismatch alone will cause UnsupportedClassVersionError. Update JAVA_HOME to point to the new JDK, then restart your terminal and IDE for the change to take effect.
Step 4: Clear the Maven or Gradle Cache
Stale compiled classes and cached dependency metadata from the old Java version can produce confusing errors completely unrelated to your actual code. Always clear the cache after a major JDK change.
Maven:
rm -rf ~/.m2/repository
mvn clean install -U
The -U flag forces Maven to re-check for updated dependency versions instead of using cached snapshots.
Gradle:
./gradlew clean build --refresh-dependencies
This single step resolves a surprising number of “it just won’t start and the error makes no sense” situations after a JDK upgrade.
Prevention: Java & Spring Boot Compatibility Reference
| Java Version | Minimum Spring Boot Version | Notes |
|---|---|---|
| Java 8 | 2.0 – 2.7.x | Spring Boot 3.x dropped support entirely |
| Java 11 | 2.1+ (recommended 2.5+) | Widely supported across the 2.x line |
| Java 17 | 3.0+ (required minimum) | javax → jakarta namespace migration required |
| Java 21 | 3.2+ | Virtual threads support added in 3.2 |
Test Checklist Before Pushing a Java Upgrade to Production
- Run the full test suite locally with the new JDK — don’t just check if the app starts
- Build a fresh jar with
mvn clean package(not an incremental build) and run it standalone, outside the IDE - Check startup logs for
WARNmessages about deprecated APIs or reflection access — these often become hard failures in later versions - If you’re also upgrading Spring Boot major versions (2.x → 3.x), do it as a separate step from the Java upgrade — debugging two major changes simultaneously is significantly harder
Conclusion
A Java upgrade that “breaks” Spring Boot is almost always one of three things: a build/runtime version mismatch, a Spring Boot version that hasn’t caught up to your new JDK, or a stale cache hiding the real error. Walk through pom.xml, confirm JAVA_HOME, and clear .m2 — in that order — and you’ll usually find the culprit before you’ve finished your coffee.
