You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/08/29 19:15:14 UTC
(maven) 05/16: Use Session properties instead of System.* in JdkToolchainDiscoverer
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
commit aa78689edc7702e62d07245ce81d47a7f038926c
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Jul 31 11:01:47 2026 +0200
Use Session properties instead of System.* in JdkToolchainDiscoverer
Replace direct System.getProperty/System.getenv calls with the
properties map from Session.getSystemProperties(), where env vars
are available as "env.VAR_NAME" entries. This follows Maven's
convention of accessing environment through the Session and makes
the discoverer fully testable without relying on JVM global state.
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
.../apache/maven/impl/DefaultToolchainManager.java | 2 +-
.../apache/maven/impl/JdkToolchainDiscoverer.java | 77 +++++++++++++---------
.../maven/impl/JdkToolchainDiscovererTest.java | 50 +++++++++++++-
3 files changed, 95 insertions(+), 34 deletions(-)
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainManager.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainManager.java
index 45df52a465..9169252983 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainManager.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainManager.java
@@ -163,7 +163,7 @@ Optional<Toolchain> autoSelectJdkToolchain(Session session) {
// 2. Fall back to lazy filesystem discovery
if (bestMatch == null && discoverer != null) {
logger.debug("No compatible JDK in configured toolchains, discovering JDKs from filesystem...");
- List<ToolchainModel> discoveredModels = discoverer.discoverToolchains();
+ List<ToolchainModel> discoveredModels = discoverer.discoverToolchains(session.getSystemProperties());
List<Toolchain> discoveredToolchains = discoveredModels.stream()
.map(this::createToolchain)
.flatMap(Optional::stream)
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/JdkToolchainDiscoverer.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/JdkToolchainDiscoverer.java
index 78524a7e6c..1d7dfe767b 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/JdkToolchainDiscoverer.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/JdkToolchainDiscoverer.java
@@ -49,6 +49,11 @@
* <p>
* JDK version is read from the {@code release} file present in every JDK since Java 9
* (and backported to JDK 8u updates), avoiding the need to execute {@code java} processes.
+ * <p>
+ * All environment and system property access goes through the {@code properties} map
+ * supplied by the caller (typically {@link org.apache.maven.api.Session#getSystemProperties()}),
+ * where environment variables are available as {@code env.VAR_NAME} entries and JVM system
+ * properties as plain keys ({@code java.home}, {@code user.home}, etc.).
*/
@Named
@Singleton
@@ -59,15 +64,20 @@ public class JdkToolchainDiscoverer {
private volatile List<ToolchainModel> cachedToolchains;
/**
- * Returns discovered JDK toolchain models. Results are cached after first invocation.
+ * Returns discovered JDK toolchain models. Results are cached after first invocation
+ * (the properties map from the first call wins; subsequent calls with different
+ * properties still return the cached result, since JDK locations don't change mid-build).
+ *
+ * @param properties system properties map (from {@code Session.getSystemProperties()}).
+ * Environment variables are expected as {@code env.VAR_NAME} entries.
*/
- public List<ToolchainModel> discoverToolchains() {
+ public List<ToolchainModel> discoverToolchains(Map<String, String> properties) {
List<ToolchainModel> result = cachedToolchains;
if (result == null) {
synchronized (this) {
result = cachedToolchains;
if (result == null) {
- result = doDiscover();
+ result = doDiscover(properties);
cachedToolchains = result;
}
}
@@ -75,11 +85,11 @@ public List<ToolchainModel> discoverToolchains() {
return result;
}
- private List<ToolchainModel> doDiscover() {
+ private List<ToolchainModel> doDiscover(Map<String, String> properties) {
Set<Path> candidates = new LinkedHashSet<>();
- collectFromEnvironment(candidates);
- collectFromToolManagers(candidates);
- collectFromSystemDirectories(candidates);
+ collectFromEnvironment(candidates, properties);
+ collectFromToolManagers(candidates, properties);
+ collectFromSystemDirectories(candidates, properties);
List<ToolchainModel> toolchains = new ArrayList<>();
for (Path candidate : candidates) {
@@ -100,34 +110,33 @@ private List<ToolchainModel> doDiscover() {
/**
* Collects JDK candidates from environment variables matching {@code JAVA*_HOME}.
+ * Environment variables are read from the properties map as {@code env.VAR_NAME} entries.
*/
- void collectFromEnvironment(Set<Path> candidates) {
- // Current JDK
- String javaHome = System.getProperty("java.home");
+ void collectFromEnvironment(Set<Path> candidates, Map<String, String> properties) {
+ // Current JDK (from java.home system property)
+ String javaHome = properties.get("java.home");
if (javaHome != null) {
addCandidate(candidates, Paths.get(javaHome));
}
- // JAVA*_HOME env vars (e.g. JAVA11_HOME, JAVA17_HOME)
- for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
+ // env.JAVA*_HOME env vars (e.g. env.JAVA11_HOME, env.JAVA17_HOME, env.JAVA_HOME)
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
String name = entry.getKey();
- if (name.startsWith("JAVA") && name.endsWith("_HOME")) {
+ if (name.startsWith("env.JAVA") && name.endsWith("_HOME")) {
addCandidate(candidates, Paths.get(entry.getValue()));
}
}
-
- // JAVA_HOME
- String envJavaHome = System.getenv("JAVA_HOME");
- if (envJavaHome != null) {
- addCandidate(candidates, Paths.get(envJavaHome));
- }
}
/**
* Collects JDK candidates from common tool manager directories under the user's home.
*/
- void collectFromToolManagers(Set<Path> candidates) {
- Path userHome = Paths.get(System.getProperty("user.home"));
+ void collectFromToolManagers(Set<Path> candidates, Map<String, String> properties) {
+ String userHomeProp = properties.get("user.home");
+ if (userHomeProp == null) {
+ return;
+ }
+ Path userHome = Paths.get(userHomeProp);
// IntelliJ IDEA / common
scanSubdirectories(candidates, userHome.resolve(".jdks"));
@@ -161,11 +170,11 @@ void collectFromToolManagers(Set<Path> candidates) {
/**
* Collects JDK candidates from OS-specific system directories.
*/
- void collectFromSystemDirectories(Set<Path> candidates) {
+ void collectFromSystemDirectories(Set<Path> candidates, Map<String, String> properties) {
if (Os.IS_WINDOWS) {
- collectWindowsDirectories(candidates);
+ collectWindowsDirectories(candidates, properties);
} else if (Os.isFamily("mac")) {
- collectMacDirectories(candidates);
+ collectMacDirectories(candidates, properties);
} else {
collectLinuxDirectories(candidates);
}
@@ -181,14 +190,17 @@ private void collectLinuxDirectories(Set<Path> candidates) {
scanSubdirectories(candidates, Paths.get("/opt/hostedtoolcache"));
}
- private void collectMacDirectories(Set<Path> candidates) {
- Path userHome = Paths.get(System.getProperty("user.home"));
+ private void collectMacDirectories(Set<Path> candidates, Map<String, String> properties) {
scanSubdirectories(candidates, Paths.get("/Library/Java/JavaVirtualMachines"));
- scanSubdirectories(
- candidates, userHome.resolve("Library").resolve("Java").resolve("JavaVirtualMachines"));
+ String userHomeProp = properties.get("user.home");
+ if (userHomeProp != null) {
+ Path userHome = Paths.get(userHomeProp);
+ scanSubdirectories(
+ candidates, userHome.resolve("Library").resolve("Java").resolve("JavaVirtualMachines"));
+ }
}
- private void collectWindowsDirectories(Set<Path> candidates) {
+ private void collectWindowsDirectories(Set<Path> candidates, Map<String, String> properties) {
Path progFiles = Paths.get("C:\\Program Files");
scanSubdirectories(candidates, progFiles.resolve("Java"));
scanSubdirectories(candidates, progFiles.resolve("Eclipse Adoptium"));
@@ -196,8 +208,11 @@ private void collectWindowsDirectories(Set<Path> candidates) {
scanSubdirectories(candidates, progFiles.resolve("Amazon Corretto"));
scanSubdirectories(candidates, progFiles.resolve("BellSoft"));
// Scoop
- Path userHome = Paths.get(System.getProperty("user.home"));
- scanSubdirectories(candidates, userHome.resolve("scoop").resolve("apps"));
+ String userHomeProp = properties.get("user.home");
+ if (userHomeProp != null) {
+ Path userHome = Paths.get(userHomeProp);
+ scanSubdirectories(candidates, userHome.resolve("scoop").resolve("apps"));
+ }
}
/**
diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/JdkToolchainDiscovererTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/JdkToolchainDiscovererTest.java
index 041a9cce1d..76d0d6e576 100644
--- a/impl/maven-impl/src/test/java/org/apache/maven/impl/JdkToolchainDiscovererTest.java
+++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/JdkToolchainDiscovererTest.java
@@ -21,7 +21,10 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.LinkedHashSet;
+import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import org.apache.maven.api.toolchain.ToolchainModel;
import org.junit.jupiter.api.Test;
@@ -157,13 +160,56 @@ void resolveJdkHomeInvalidPath() {
@Test
void discoverToolchainsIsCached() {
+ Map<String, String> properties = Map.of("user.home", tempDir.toString());
// Two calls should return the same list instance (cached)
- var first = discoverer.discoverToolchains();
- var second = discoverer.discoverToolchains();
+ var first = discoverer.discoverToolchains(properties);
+ var second = discoverer.discoverToolchains(properties);
assertNotNull(first);
assertTrue(first == second, "Expected cached result (same instance)");
}
+ @Test
+ void collectFromEnvironmentUsesProperties() throws IOException {
+ Path jdkHome = createFakeJdk(tempDir, "jdk-21");
+ Map<String, String> properties = Map.of(
+ "java.home", jdkHome.toString(),
+ "env.JAVA17_HOME", tempDir.resolve("jdk-17-env").toString());
+
+ Set<Path> candidates = new LinkedHashSet<>();
+ discoverer.collectFromEnvironment(candidates, properties);
+
+ assertTrue(candidates.stream().anyMatch(p -> p.toString().contains("jdk-21")), "Should include java.home");
+ assertTrue(
+ candidates.stream().anyMatch(p -> p.toString().contains("jdk-17-env")),
+ "Should include env.JAVA17_HOME");
+ }
+
+ @Test
+ void collectFromToolManagersUsesProperties() throws IOException {
+ Path fakeHome = tempDir.resolve("fakehome");
+ Path jdksDir = fakeHome.resolve(".jdks");
+ Path jdk21 = jdksDir.resolve("temurin-21");
+ Files.createDirectories(jdk21);
+
+ Map<String, String> properties = Map.of("user.home", fakeHome.toString());
+
+ Set<Path> candidates = new LinkedHashSet<>();
+ discoverer.collectFromToolManagers(candidates, properties);
+
+ assertTrue(
+ candidates.stream().anyMatch(p -> p.toString().contains("temurin-21")), "Should find JDK in ~/.jdks");
+ }
+
+ @Test
+ void collectFromToolManagersSkipsWhenNoUserHome() {
+ Map<String, String> properties = Map.of();
+
+ Set<Path> candidates = new LinkedHashSet<>();
+ discoverer.collectFromToolManagers(candidates, properties);
+
+ assertTrue(candidates.isEmpty(), "Should collect nothing without user.home");
+ }
+
private Path createFakeJdk(Path parent, String name) throws IOException {
Path jdkHome = parent.resolve(name);
Path binDir = jdkHome.resolve("bin");