From 840e952229d29b41d0c80350aa7f6bae118f7ec2 Mon Sep 17 00:00:00 2001 From: Slawomir Jaranowski Date: Wed, 15 Apr 2026 23:53:56 +0200 Subject: [PATCH] Promote java version in JavaToolchain Many plugins using toolchains has requirements to detect java version selected by toolchains in runtime. Expose java version in JavaToolchain can simplify plugins code. (cherry picked from commit 528a0f001a452401c228f6d2b04e661e969ceb19) --- .../org/apache/maven/api/JavaToolchain.java | 2 + .../maven/toolchain/java/JavaToolchain.java | 7 +- .../toolchain/java/JavaToolchainFactory.java | 11 +++ .../toolchain/java/JavaToolchainImpl.java | 12 +++ .../java/JavaToolchainFactoryTest.java | 94 ++++++++++++++++++ .../impl/DefaultJavaToolchainFactory.java | 20 +++- .../impl/DefaultJavaToolchainFactoryTest.java | 97 +++++++++++++++++++ 7 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 compat/maven-compat/src/test/java/org/apache/maven/toolchain/java/JavaToolchainFactoryTest.java create mode 100644 impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultJavaToolchainFactoryTest.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaToolchain.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaToolchain.java index a4addddac79a..5357af9ac4e9 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaToolchain.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaToolchain.java @@ -42,4 +42,6 @@ public interface JavaToolchain extends Toolchain { String getJavaHome(); + + Version getJavaVersion(); } diff --git a/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java b/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java index 6080f00f4d79..300f80f75f2e 100644 --- a/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java +++ b/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java @@ -18,6 +18,7 @@ */ package org.apache.maven.toolchain.java; +import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.toolchain.Toolchain; /** @@ -27,4 +28,8 @@ * @deprecated Use {@link org.apache.maven.api.JavaToolchain} instead. */ @Deprecated(since = "4.0.0") -public interface JavaToolchain extends Toolchain {} +public interface JavaToolchain extends Toolchain { + String getJavaHome(); + + ArtifactVersion getJavaVersion(); +} diff --git a/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java b/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java index f22884ce6494..3802b45538c4 100644 --- a/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java +++ b/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java @@ -21,9 +21,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; import java.util.Map.Entry; import java.util.Properties; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.toolchain.MisconfiguredToolchainException; import org.apache.maven.toolchain.RequirementMatcher; import org.apache.maven.toolchain.RequirementMatcherFactory; @@ -93,6 +96,14 @@ public ToolchainPrivate createToolchain(ToolchainModel model) throws Misconfigur "Non-existing JDK home configuration at " + normal.toAbsolutePath()); } + ArtifactVersion javaVersion = model.getProvides().entrySet().stream() + .filter(entry -> "version".equals(entry.getKey())) + .map(Map.Entry::getValue) + .map(v -> new DefaultArtifactVersion((String) v)) + .findAny() + .orElse(null); + + jtc.setJavaVersion(javaVersion); return jtc; } diff --git a/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java b/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java index 661ffa642455..c4a837c07b2b 100644 --- a/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java +++ b/compat/maven-compat/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java @@ -22,6 +22,7 @@ import java.nio.file.Path; import java.nio.file.Paths; +import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.toolchain.DefaultToolchain; import org.apache.maven.toolchain.model.ToolchainModel; import org.apache.maven.utils.Os; @@ -39,6 +40,8 @@ public class JavaToolchainImpl extends DefaultToolchain implements JavaToolchain public static final String KEY_JAVAHOME = "jdkHome"; // NOI18N + private ArtifactVersion javaVersion; + JavaToolchainImpl(ToolchainModel model, Logger logger) { super(model, "jdk", logger); } @@ -47,6 +50,15 @@ public String getJavaHome() { return javaHome; } + @Override + public ArtifactVersion getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(ArtifactVersion javaVersion) { + this.javaVersion = javaVersion; + } + public void setJavaHome(String javaHome) { this.javaHome = javaHome; } diff --git a/compat/maven-compat/src/test/java/org/apache/maven/toolchain/java/JavaToolchainFactoryTest.java b/compat/maven-compat/src/test/java/org/apache/maven/toolchain/java/JavaToolchainFactoryTest.java new file mode 100644 index 000000000000..8589426f1b08 --- /dev/null +++ b/compat/maven-compat/src/test/java/org/apache/maven/toolchain/java/JavaToolchainFactoryTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.toolchain.java; + +import org.apache.maven.toolchain.MisconfiguredToolchainException; +import org.apache.maven.toolchain.model.ToolchainModel; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SuppressWarnings("deprecation") +class JavaToolchainFactoryTest { + + private JavaToolchainFactory factory; + + @BeforeEach + void setup() { + factory = new JavaToolchainFactory(); + } + + @Test + void defaultToolchainShouldReturnEmpty() { + assertNull(factory.createDefaultToolchain()); + } + + @Test + void missingJdkHomeShouldThrowException() { + ToolchainModel toolchainModel = new ToolchainModel(); + MisconfiguredToolchainException exception = Assertions.assertThrows( + MisconfiguredToolchainException.class, () -> factory.createToolchain(toolchainModel)); + assertEquals("Java toolchain without the jdkHome configuration element.", exception.getMessage()); + } + + @Test + void nonExistingJdkHomeShouldThrowException() { + ToolchainModel toolchainModel = new ToolchainModel(); + Xpp3Dom jdkHome = new Xpp3Dom("jdkHome"); + jdkHome.setValue("/not-exist/jdk/home"); + Xpp3Dom configuration = new Xpp3Dom("configuration"); + configuration.addChild(jdkHome); + toolchainModel.setConfiguration(configuration); + + MisconfiguredToolchainException exception = Assertions.assertThrows( + MisconfiguredToolchainException.class, () -> factory.createToolchain(toolchainModel)); + assertTrue( + exception.getMessage().contains("Non-existing JDK home configuration at"), + "Not expected exception message: '" + exception.getMessage()); + assertTrue( + exception.getMessage().contains("not-exist"), + "Not expected exception message: '" + exception.getMessage() + "', should contain: 'not-exist'"); + } + + @Test + void properToolchainShouldReturnJavaToolchain() throws Exception { + String javaHome = System.getProperty("java.home"); + String javaVersion = System.getProperty("java.version"); + + ToolchainModel toolchainModel = new ToolchainModel(); + Xpp3Dom jdkHome = new Xpp3Dom("jdkHome"); + jdkHome.setValue(javaHome); + Xpp3Dom configuration = new Xpp3Dom("configuration"); + configuration.addChild(jdkHome); + toolchainModel.setConfiguration(configuration); + + toolchainModel.addProvide("version", javaVersion); + + JavaToolchain toolchain = (JavaToolchain) factory.createToolchain(toolchainModel); + assertNotNull(toolchain); + assertEquals(javaHome, toolchain.getJavaHome()); + assertEquals(javaVersion, toolchain.getJavaVersion().toString()); + } +} diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultJavaToolchainFactory.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultJavaToolchainFactory.java index 2d1383904286..d307b507a0b8 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultJavaToolchainFactory.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultJavaToolchainFactory.java @@ -87,7 +87,14 @@ public JavaToolchain createToolchain(@Nonnull ToolchainModel model) { } String javaHome = normal.toString(); - return new DefaultJavaToolchain(model, javaHome, matchers); + Version javaVersion = model.getProvides().entrySet().stream() + .filter(entry -> "version".equals(entry.getKey())) + .map(Map.Entry::getValue) + .map(versionParser::parseVersion) + .findAny() + .orElse(null); + + return new DefaultJavaToolchain(model, javaHome, javaVersion, matchers); } @Nonnull @@ -102,9 +109,13 @@ static class DefaultJavaToolchain implements JavaToolchain { final String javaHome; final Map> matchers; - DefaultJavaToolchain(ToolchainModel model, String javaHome, Map> matchers) { + private Version javaVersion; + + DefaultJavaToolchain( + ToolchainModel model, String javaHome, Version javaVersion, Map> matchers) { this.model = model; this.javaHome = javaHome; + this.javaVersion = javaVersion; this.matchers = matchers; } @@ -113,6 +124,11 @@ public String getJavaHome() { return javaHome; } + @Override + public Version getJavaVersion() { + return javaVersion; + } + @Override public String getType() { return "jdk"; diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultJavaToolchainFactoryTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultJavaToolchainFactoryTest.java new file mode 100644 index 000000000000..387d08f65bbc --- /dev/null +++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultJavaToolchainFactoryTest.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.impl; + +import java.util.List; +import java.util.Map; + +import org.apache.maven.api.JavaToolchain; +import org.apache.maven.api.services.ToolchainFactoryException; +import org.apache.maven.api.services.VersionParser; +import org.apache.maven.api.toolchain.ToolchainModel; +import org.apache.maven.api.xml.XmlNode; +import org.apache.maven.impl.resolver.MavenVersionScheme; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class DefaultJavaToolchainFactoryTest { + + private DefaultJavaToolchainFactory factory; + + @BeforeEach + void setUp() { + VersionParser versionParser = new DefaultVersionParser(new DefaultModelVersionParser(new MavenVersionScheme())); + factory = new DefaultJavaToolchainFactory(versionParser); + } + + @Test + void defaultToolchainShouldReturnEmpty() { + assertTrue(factory.createDefaultToolchain().isEmpty()); + } + + @Test + void missingJdkHomeShouldThrowException() { + ToolchainModel toolchainModel = ToolchainModel.newBuilder().build(); + ToolchainFactoryException exception = + Assertions.assertThrows(ToolchainFactoryException.class, () -> factory.createToolchain(toolchainModel)); + assertEquals("Java toolchain without the jdkHome configuration element.", exception.getMessage()); + } + + @Test + void nonExistingJdkHomeShouldThrowException() { + ToolchainModel toolchainModel = ToolchainModel.newBuilder() + .configuration(XmlNode.newBuilder() + .name("configuration") + .children(List.of(XmlNode.newInstance("jdkHome", "/not-exist/jdk/home"))) + .build()) + .build(); + + ToolchainFactoryException exception = + Assertions.assertThrows(ToolchainFactoryException.class, () -> factory.createToolchain(toolchainModel)); + assertTrue( + exception.getMessage().contains("Non-existing JDK home configuration at"), + "Not expected exception message: '" + exception.getMessage()); + assertTrue( + exception.getMessage().contains("not-exist"), + "Not expected exception message: '" + exception.getMessage() + "', should contain: 'not-exist'"); + } + + @Test + void properToolchainShouldReturnJavaToolchain() { + String javaHome = System.getProperty("java.home"); + String javaVersion = System.getProperty("java.version"); + ToolchainModel toolchainModel = ToolchainModel.newBuilder() + .provides(Map.of("version", javaVersion)) + .configuration(XmlNode.newBuilder() + .name("configuration") + .children(List.of(XmlNode.newInstance("jdkHome", javaHome))) + .build()) + .build(); + + JavaToolchain toolchain = factory.createToolchain(toolchainModel); + assertNotNull(toolchain); + assertEquals(javaHome, toolchain.getJavaHome()); + assertEquals(javaVersion, toolchain.getJavaVersion().toString()); + } +}