Masoud Hamad

Windows — JDK 21 + Maven + JAVA_HOME

The single most common Lab 6 / Spring Boot blocker on Windows is a broken JAVA_HOME or PATH. This guide takes you from a clean Windows install to a working mvn -version showing Java 21.

Pick your path: if you have Windows 11 (or Windows 10 with App Installer), use Path A — winget. Otherwise use Path B — manual installers.

When in doubt, start with Path A. Jump to verification at the end of either path.


What you need at the end

java -version
# openjdk version "21.0.x" 2024-xx-xx

mvn -version
# Apache Maven 3.9.x
# Java version: 21.0.x, vendor: Eclipse Adoptium

echo $env:JAVA_HOME
# C:\Program Files\Eclipse Adoptium\jdk-21.0.x.X-hotspot

If all three commands work in a fresh PowerShell window, you’re done.


Path A — winget (one-liner, fastest)

1. Open PowerShell as Administrator

Press Win, type “powershell”, right-click → Run as administrator.

2. Install JDK 21 and Maven

winget install --id EclipseAdoptium.Temurin.21.JDK
winget install --id Apache.Maven

💡 What just happened. winget pulled the official Temurin (Eclipse Adoptium) JDK 21 and Apache Maven installers, ran them, and added the JDK to PATH automatically. Maven from winget does NOT set JAVA_HOME for you, and older Temurin installers also skip it — that’s the actual bug behind 90 % of the lab failures.

3. Set JAVA_HOME manually

Find your exact JDK install path:

Get-ChildItem 'C:\Program Files\Eclipse Adoptium'

You’ll see something like jdk-21.0.4.7-hotspot. Copy that folder name, then:

[Environment]::SetEnvironmentVariable(
    'JAVA_HOME',
    'C:\Program Files\Eclipse Adoptium\jdk-21.0.4.7-hotspot',
    'Machine'
)

💡 Why 'Machine'? That writes it to the system environment so every user and every shell sees it. 'User' would limit it to the current Windows user — fine for a personal laptop, but inconsistent if you ever switch accounts.

4. Add the JDK bin to PATH

The winget installer usually does this, but verify:

$javaBin = "$env:JAVA_HOME\bin"
$current = [Environment]::GetEnvironmentVariable('Path', 'Machine')

if ($current -notlike "*$javaBin*") {
    [Environment]::SetEnvironmentVariable(
        'Path', "$current;$javaBin", 'Machine'
    )
    Write-Host "Added $javaBin to system PATH"
} else {
    Write-Host "Already on PATH"
}

5. Close PowerShell and open a new window (Administrator no longer needed)

Environment variables only take effect in new processes. Skip this and java -version will keep showing the old value.

Jump to verification.


Path B — Manual installers

Use this if you’re on Windows 10 without winget, behind a corporate proxy, or you prefer GUI installers.

1. Download the JDK

Go to https://adoptium.net/temurin/releases/?version=21&os=windows.

Pick:

Click the .msi link, run it.

In the installer, on the “Custom Setup” screen, expand every option and choose “Will be installed on local hard drive” for:

If you only check JAVA_HOME, the rest still work — but ticking all three saves headaches later.

💡 Why this matters. If you don’t tick Set JAVA_HOME variable, the installer skips it and you’ll set it by hand below. Not the end of the world — just an extra step.

2. Download Maven

Go to https://maven.apache.org/download.cgi.

Under Files, click Binary zip archive (e.g. apache-maven-3.9.9-bin.zip).

3. Install Maven (it’s just an unzip)

Right-click the zip → Extract All… → extract to:

C:\Program Files\Apache\

You should now have:

C:\Program Files\Apache\apache-maven-3.9.9\
├── bin\
├── boot\
├── conf\
└── lib\

💡 Why a non-user folder? Putting it in C:\Program Files\Apache\ makes it a system-wide install. If you put it under C:\Users\YourName\ only your account can run it.

4. Set environment variables in the GUI

This is the place students get lost. Take it slow.

  1. Press Win, type “environment variables”, click “Edit the system environment variables”.
  2. Click the “Environment Variables…” button at the bottom right.
  3. In the lower box (“System variables”), click New…:

    • Variable name: JAVA_HOME
    • Variable value: C:\Program Files\Eclipse Adoptium\jdk-21.0.4.7-hotspot
    • (Use the actual folder name on your machine — open C:\Program Files\Eclipse Adoptium\ and copy it.)
    • Click OK.
  4. Still in the lower box, click New… again:

    • Variable name: MAVEN_HOME
    • Variable value: C:\Program Files\Apache\apache-maven-3.9.9
    • Click OK.
  5. Still in the lower box, scroll to find Path, select it, click Edit…, then New and add two entries:

    %JAVA_HOME%\bin
    %MAVEN_HOME%\bin
    

    Click OK on every dialog to close all of them.

⚠️ Edit “System variables”, not “User variables”. They’re two separate boxes in the same dialog. Setting them under “User variables” works for one account; “System variables” works for everyone.

5. Close every PowerShell / CMD window and open a new one

Same rule as Path A — env vars only apply to new processes. Some Windows 10 builds also need a sign-out / sign-in for VS Code and IntelliJ to pick up the change.


5. Verify everything works

Open a fresh PowerShell (or CMD) and run all four:

java -version
javac -version
mvn -version
echo $env:JAVA_HOME

You should see:

openjdk version "21.0.4" 2024-xx-xx
javac 21.0.4
Apache Maven 3.9.9 (...)
Maven home: C:\Program Files\Apache\apache-maven-3.9.9
Java version: 21.0.4, vendor: Eclipse Adoptium, runtime: C:\Program Files\Eclipse Adoptium\jdk-21.0.4.7-hotspot
C:\Program Files\Eclipse Adoptium\jdk-21.0.4.7-hotspot

If any of those four show a different number or fail, scroll to Troubleshooting.

Quick Maven sanity test

This actually downloads dependencies and runs a tiny Spring Boot starter — proves Maven, Java, and your network all work together.

mkdir C:\temp\mvntest
cd C:\temp\mvntest
mvn archetype:generate -DgroupId=hello -DartifactId=hello -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
cd hello
mvn -q -DskipTests compile

If the last command finishes silently, you’re fully set up. Delete the folder when done:

cd ..\..
Remove-Item -Recurse -Force C:\temp\mvntest

Troubleshooting

'java' is not recognized as an internal or external command

PATH isn’t picking up Java.

# In a NEW PowerShell:
echo $env:Path

Look for ...jdk-21...\bin. If it’s missing, you didn’t add it (Path A step 4 or Path B step 4). If it’s there but Java still can’t be found, the folder name in JAVA_HOME is wrong — re-check with:

Get-ChildItem 'C:\Program Files\Eclipse Adoptium'

…and use the exact folder name shown.

java -version shows the wrong version (e.g. Java 8 or 17)

You have another JDK earlier on PATH. Find them all:

where.exe java

If multiple lines come back, the first one wins. Remove the unwanted ones from PATH, or put %JAVA_HOME%\bin ahead of them in the system Path editor.

mvn -version shows the wrong Java

Maven uses JAVA_HOME, not PATH. So if Maven reports e.g. Java 17 while java -version reports 21, JAVA_HOME is still pointing at the old JDK.

echo $env:JAVA_HOME
# Should print the JDK 21 path, not 17

If it’s wrong, repeat Path A step 3 (or Path B step 4), then open a brand-new shell.

'mvn' is not recognized…

Same as Java — %MAVEN_HOME%\bin isn’t on PATH. Re-check Path B step 4, or for Path A confirm winget actually installed Maven:

winget list Apache.Maven

Environment variables look right but PowerShell ignores them

PowerShell caches env vars per process. The fix is always close every shell and open a new one. If even that doesn’t work, sign out of Windows and back in.

IntelliJ / VS Code uses the wrong JDK

GUIs cache JAVA_HOME from whenever they were started.

Behind a corporate / university proxy → mvn can’t download anything

Edit (or create) C:\Users\YourName\.m2\settings.xml:

<settings>
  <proxies>
    <proxy>
      <id>uniproxy</id>
      <active>true</active>
      <protocol>http</protocol>
      <host>proxy.suza.ac.tz</host>
      <port>8080</port>
      <username>YOURUSER</username>
      <password>YOURPASS</password>
      <nonProxyHosts>localhost</nonProxyHosts>
    </proxy>
  </proxies>
</settings>

Replace host/port with the values from the IT department.

winget itself doesn’t exist

You’re on an older Windows 10 build. Either:

Windows Defender blocks the installer

Right-click the .msiProperties → tick Unblock at the bottom → Apply. Then re-run.

Still stuck?

Bring your laptop to lab. Don’t fight env vars alone for hours — they’re a known time sink and we have a checklist that resolves 95 % of cases in 5 minutes.


Why we need all this

Thing What it does Why it’s required
JDK 21 Compiles and runs Java code Spring Boot 3 requires Java 17+; we standardise on 21
Maven Downloads dependencies, builds the project mvn spring-boot:run is how we start the app
JAVA_HOME Tells Maven (and IntelliJ, VS Code, Gradle, …) which JDK to use Without it, Maven uses whatever java it finds on PATH — which might be Java 8 from another install
PATH Tells the shell which folders to search for executables Without %JAVA_HOME%\bin and %MAVEN_HOME%\bin on PATH, the commands don’t exist

You only set this up once per machine. After that, every Spring Boot lab Just Works.