diff --git a/pom.xml b/pom.xml
index 667ea5c..12f3007 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,6 +79,18 @@
2022-09-12T15:53:21Z
+
+
+
+ org.junit
+ junit-bom
+ 5.10.1
+ pom
+ import
+
+
+
+
org.apache.maven
@@ -123,33 +135,31 @@
- junit
- junit
- 4.13.2
+ org.junit.jupiter
+ junit-jupiter-api
test
org.apache.maven.plugin-testing
maven-plugin-testing-harness
- 3.3.0
+ 4.0.0-alpha-2
test
- org.apache.maven
- maven-compat
- ${mavenVersion}
+ org.mockito
+ mockito-core
+ 4.11.0
test
- commons-io
- commons-io
- 2.15.1
+ org.mockito
+ mockito-junit-jupiter
+ 4.11.0
test
org.codehaus.plexus
plexus-xml
- 3.0.0
test
@@ -178,6 +188,13 @@
+
+
+
+ org.eclipse.sisu
+ sisu-maven-plugin
+
+
diff --git a/src/it/MJAR-62-toolchain/invoker.properties b/src/it/MJAR-62-toolchain/invoker.properties
new file mode 100644
index 0000000..9904dcc
--- /dev/null
+++ b/src/it/MJAR-62-toolchain/invoker.properties
@@ -0,0 +1,18 @@
+# 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.
+
+invoker.toolchain.jdk.version = 17
\ No newline at end of file
diff --git a/src/it/MJAR-62-toolchain/pom.xml b/src/it/MJAR-62-toolchain/pom.xml
new file mode 100644
index 0000000..610d560
--- /dev/null
+++ b/src/it/MJAR-62-toolchain/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+ 4.0.0
+ org.apache.maven.plugins
+ mjar-62
+ MJAR-62
+ jar
+ 1.0-SNAPSHOT
+
+ jar plugin it
+
+
+
+
+ junit
+ junit
+ 4.13.2
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-toolchains-plugin
+ 3.1.0
+
+
+
+ toolchain
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ @project.version@
+
+
+
+
diff --git a/src/it/MJAR-62-toolchain/src/main/java/myproject/HelloWorld.java b/src/it/MJAR-62-toolchain/src/main/java/myproject/HelloWorld.java
new file mode 100644
index 0000000..fd0ad83
--- /dev/null
+++ b/src/it/MJAR-62-toolchain/src/main/java/myproject/HelloWorld.java
@@ -0,0 +1,36 @@
+package myproject;
+
+/*
+ * 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.
+ */
+
+/**
+ * The classic Hello World App.
+ */
+public class HelloWorld {
+
+ /**
+ * Main method.
+ *
+ * @param args Not used
+ */
+ public static void main( String[] args )
+ {
+ System.out.println( "Hi!" );
+ }
+}
\ No newline at end of file
diff --git a/src/it/MJAR-62-toolchain/verify.groovy b/src/it/MJAR-62-toolchain/verify.groovy
new file mode 100644
index 0000000..4fdf714
--- /dev/null
+++ b/src/it/MJAR-62-toolchain/verify.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+import java.util.jar.JarFile
+
+def mrjar = new JarFile(new File(basedir, 'target/mjar-62-1.0-SNAPSHOT.jar'))
+def manifest = mrjar.manifest.mainAttributes
+
+assert manifest.getValue("Build-Jdk-Spec") == "17"
+assert manifest.getValue("Build-Tool-Jdk-Spec") == System.getProperty("java.specification.version")
diff --git a/src/main/java/org/apache/maven/plugins/jar/AbstractJarMojo.java b/src/main/java/org/apache/maven/plugins/jar/AbstractJarMojo.java
index ab2a50f..47b8bde 100644
--- a/src/main/java/org/apache/maven/plugins/jar/AbstractJarMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jar/AbstractJarMojo.java
@@ -22,6 +22,7 @@
import java.nio.file.FileSystems;
import java.util.Arrays;
import java.util.Map;
+import java.util.Optional;
import org.apache.maven.archiver.MavenArchiveConfiguration;
import org.apache.maven.archiver.MavenArchiver;
@@ -34,6 +35,7 @@
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.shared.model.fileset.FileSet;
import org.apache.maven.shared.model.fileset.util.FileSetManager;
+import org.apache.maven.toolchain.ToolchainManager;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.jar.JarArchiver;
@@ -53,6 +55,12 @@ public abstract class AbstractJarMojo extends AbstractMojo {
private static final String SEPARATOR = FileSystems.getDefault().getSeparator();
+ @Component
+ private ToolchainsJdkSpecification toolchainsJdkSpecification;
+
+ @Component
+ private ToolchainManager toolchainManager;
+
/**
* List of files to include. Specified as fileset patterns which are relative to the input directory whose contents
* is being packaged into the JAR.
@@ -250,6 +258,17 @@ public File createArchive() throws MojoExecutionException {
archiver.setArchiver((JarArchiver) archivers.get(archiverName));
archiver.setOutputFile(jarFile);
+ Optional.ofNullable(toolchainManager.getToolchainFromBuildContext("jdk", session))
+ .ifPresent(toolchain -> toolchainsJdkSpecification
+ .getJDKSpecification(toolchain)
+ .ifPresent(jdkSpec -> {
+ archive.addManifestEntry("Build-Jdk-Spec", jdkSpec);
+ archive.addManifestEntry(
+ "Build-Tool-Jdk-Spec", System.getProperty("java.specification.version"));
+ archiver.setBuildJdkSpecDefaultEntry(false);
+ getLog().info("Set Build-Jdk-Spec based on toolchain in maven-jar-plugin " + toolchain);
+ }));
+
// configure for Reproducible Builds based on outputTimestamp value
archiver.configureReproducibleBuild(outputTimestamp);
diff --git a/src/main/java/org/apache/maven/plugins/jar/ToolchainsJdkSpecification.java b/src/main/java/org/apache/maven/plugins/jar/ToolchainsJdkSpecification.java
new file mode 100644
index 0000000..8872632
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/jar/ToolchainsJdkSpecification.java
@@ -0,0 +1,99 @@
+/*
+ * 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.plugins.jar;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.maven.toolchain.Toolchain;
+import org.codehaus.plexus.util.cli.CommandLineException;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Component provided JDK specification based on toolchains.
+ */
+@Named
+@Singleton
+class ToolchainsJdkSpecification {
+
+ private final Logger logger = LoggerFactory.getLogger(ToolchainsJdkSpecification.class);
+
+ private final Map cache = new HashMap<>();
+
+ public synchronized Optional getJDKSpecification(Toolchain toolchain) {
+ Optional javacPath = getJavacPath(toolchain);
+ return javacPath.map(path -> cache.computeIfAbsent(path, this::getSpecForPath));
+ }
+
+ private Optional getJavacPath(Toolchain toolchain) {
+ return Optional.ofNullable(toolchain.findTool("javac")).map(Paths::get).map(this::getCanonicalPath);
+ }
+
+ private Path getCanonicalPath(Path path) {
+ try {
+ return path.toRealPath();
+ } catch (IOException e) {
+ if (path.getParent() != null) {
+ return getCanonicalPath(path.getParent()).resolve(path.getFileName());
+ } else {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+
+ private String getSpecForPath(Path path) {
+ try {
+ Commandline cl = new Commandline(path.toString());
+ cl.createArg().setValue("-version");
+ CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
+ CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
+ CommandLineUtils.executeCommandLine(cl, out, err);
+ String version = out.getOutput().trim();
+ if (version.isEmpty()) {
+ version = err.getOutput().trim();
+ }
+ if (version.startsWith("javac ")) {
+ version = version.substring(6);
+ if (version.startsWith("1.")) {
+ version = version.substring(0, 3);
+ } else {
+ version = version.substring(0, 2);
+ }
+ return version;
+ } else {
+ logger.warn("Unrecognized output form " + path + " -version - " + version);
+ return null;
+ }
+ } catch (CommandLineException | IndexOutOfBoundsException e) {
+ logger.warn("Failed to execute: " + path + " - " + e.getMessage());
+ return null;
+ }
+ }
+}
diff --git a/src/test/java/org/apache/maven/plugins/jar/JarMojoTest.java b/src/test/java/org/apache/maven/plugins/jar/JarMojoTest.java
index 11c0696..b8b57e8 100644
--- a/src/test/java/org/apache/maven/plugins/jar/JarMojoTest.java
+++ b/src/test/java/org/apache/maven/plugins/jar/JarMojoTest.java
@@ -18,28 +18,28 @@
*/
package org.apache.maven.plugins.jar;
-import java.io.File;
+import org.apache.maven.plugin.testing.junit5.InjectMojo;
+import org.apache.maven.plugin.testing.junit5.MojoTest;
+import org.junit.jupiter.api.Test;
-import org.apache.maven.plugin.testing.AbstractMojoTestCase;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* Test for {@link JarMojo}
*
* @version $Id$
*/
-public class JarMojoTest extends AbstractMojoTestCase {
- private File testPom = new File(getBasedir(), "src/test/resources/unit/jar-basic-test/pom.xml");
+@MojoTest
+class JarMojoTest {
/**
* Tests the discovery and configuration of the mojo.
- *
- * @throws Exception in case of an error
*/
- public void testJarTestEnvironment() throws Exception {
- JarMojo mojo = (JarMojo) lookupMojo("jar", testPom);
-
+ @Test
+ @InjectMojo(goal = "jar", pom = "classpath:/unit/jar-basic-test/pom.xml")
+ void testJarTestEnvironment(JarMojo mojo) {
assertNotNull(mojo);
-
assertEquals("foo", mojo.getProject().getGroupId());
}
}
diff --git a/src/test/java/org/apache/maven/plugins/jar/ToolchainsJdkVersionTest.java b/src/test/java/org/apache/maven/plugins/jar/ToolchainsJdkVersionTest.java
new file mode 100644
index 0000000..0d504ed
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugins/jar/ToolchainsJdkVersionTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.plugins.jar;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Locale;
+import java.util.Optional;
+
+import org.apache.maven.toolchain.Toolchain;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class ToolchainsJdkVersionTest {
+
+ @Mock
+ private Toolchain toolchain;
+
+ private final ToolchainsJdkSpecification toolchainsJdkSpecification = new ToolchainsJdkSpecification();
+
+ @Test
+ void shouldReturnCorrectSpec() {
+
+ Path javacPath = getJavacPath();
+ Assumptions.assumeTrue(Files.isExecutable(javacPath));
+
+ when(toolchain.findTool("javac")).thenReturn(javacPath.toString());
+
+ Optional jdkVersion = toolchainsJdkSpecification.getJDKSpecification(toolchain);
+ Assertions.assertTrue(jdkVersion.isPresent());
+ Assertions.assertEquals(System.getProperty("java.specification.version"), jdkVersion.get());
+ }
+
+ @Test
+ void shouldReturnEmptySpec() {
+
+ when(toolchain.findTool("javac")).thenReturn(null);
+
+ Optional jdkVersion = toolchainsJdkSpecification.getJDKSpecification(toolchain);
+ Assertions.assertFalse(jdkVersion.isPresent());
+ }
+
+ private String getJavaCName() {
+ if (System.getProperty("os.name", "").toLowerCase(Locale.ROOT).startsWith("win")) {
+ return "javac.exe";
+ } else {
+ return "javac";
+ }
+ }
+
+ private Path getJavacPath() {
+ String javaCName = getJavaCName();
+
+ String javaHome = System.getProperty("java.home");
+
+ Path javacPath = Paths.get(javaHome, "bin", javaCName);
+ if (Files.isExecutable(javacPath)) {
+ return javacPath;
+ }
+
+ // try with jre
+ return Paths.get(javaHome, "../bin", javaCName);
+ }
+}