maven-surefire git commit: [SUREFIRE-1403] [Jigsaw] [Java 9] add "--add-modules ALL-SYSTEM" to forked CLI argument [Forced Update!]

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

maven-surefire git commit: [SUREFIRE-1403] [Jigsaw] [Java 9] add "--add-modules ALL-SYSTEM" to forked CLI argument [Forced Update!]

Tibor Digana
Repository: maven-surefire
Updated Branches:
  refs/heads/SUREFIRE-1403 b622b04fe -> 1922adaf3 (forced update)


[SUREFIRE-1403] [Jigsaw] [Java 9] add "--add-modules ALL-SYSTEM" to forked CLI argument


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/1922adaf
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/1922adaf
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/1922adaf

Branch: refs/heads/SUREFIRE-1403
Commit: 1922adaf3495cc7be1a566b44680d7b3d6c3b121
Parents: 1a65d61
Author: Tibor17 <[hidden email]>
Authored: Mon Aug 7 12:43:17 2017 +0200
Committer: Tibor17 <[hidden email]>
Committed: Sat Aug 12 17:50:52 2017 +0200

----------------------------------------------------------------------
 maven-surefire-common/pom.xml                   |   2 +-
 .../plugin/surefire/AbstractSurefireMojo.java   |  72 +++-
 .../maven/plugin/surefire/JdkAttributes.java    |  48 +++
 .../booterclient/ForkConfiguration.java         |  72 ++--
 .../surefire/report/StatelessXmlReporter.java   |   4 +-
 ...erDeserializerProviderConfigurationTest.java |   2 +-
 ...terDeserializerStartupConfigurationTest.java |   2 +-
 .../booterclient/ForkConfigurationTest.java     |  65 ++--
 pom.xml                                         |  22 +-
 surefire-api/pom.xml                            |   2 +-
 surefire-booter/pom.xml                         |   8 +-
 .../maven/surefire/booter/SystemUtils.java      | 143 +++++++-
 .../maven/surefire/booter/SystemUtilsTest.java  | 330 +++++++++++++++----
 surefire-booter/src/test/resources/jdk/bin/java |   0
 .../src/test/resources/jdk/jre/bin/java         |   0
 .../src/test/resources/jdk8-IBM/release         |   1 +
 .../src/test/resources/jdk8-oracle/release      |   1 +
 .../src/test/resources/jdk9-oracle/release      |   1 +
 surefire-integration-tests/pom.xml              |   6 +-
 .../maven/surefire/its/AbstractJigsawIT.java    | 113 +++++++
 .../maven/surefire/its/Java9FullApiIT.java      |  95 ++++++
 .../surefire/its/jiras/Surefire1265Java9IT.java |  17 +-
 .../src/test/resources/java9-full-api/pom.xml   | 108 ++++++
 .../java9-full-api/src/test/java/J9Test.java    |  38 +++
 surefire-setup-integration-tests/pom.xml        |  26 +-
 .../src/main/resources/toolchains.xml           |  35 ++
 26 files changed, 1066 insertions(+), 147 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/pom.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-common/pom.xml b/maven-surefire-common/pom.xml
index ae050c7..121609b 100644
--- a/maven-surefire-common/pom.xml
+++ b/maven-surefire-common/pom.xml
@@ -160,7 +160,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <jvm>${test.jre}/bin/java</jvm>
+          <jvm>${jdk.home}/bin/java</jvm>
           <redirectTestOutputToFile>true</redirectTestOutputToFile>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index f2e5bfb..047f7a4 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -77,6 +77,7 @@ import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.apache.maven.surefire.util.DefaultScanResult;
 import org.apache.maven.surefire.util.RunOrder;
 import org.apache.maven.surefire.util.SurefireReflectionException;
+import org.apache.maven.toolchain.DefaultToolchain;
 import org.apache.maven.toolchain.Toolchain;
 import org.apache.maven.toolchain.ToolchainManager;
 
@@ -100,13 +101,21 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import static java.lang.Thread.currentThread;
+import static java.util.Collections.singletonMap;
 import static org.apache.commons.lang3.JavaVersion.JAVA_1_7;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
 import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
 import static org.apache.maven.shared.utils.StringUtils.capitalizeFirstLetter;
 import static org.apache.maven.shared.utils.StringUtils.isEmpty;
 import static org.apache.maven.shared.utils.StringUtils.isNotBlank;
+import static org.apache.maven.shared.utils.StringUtils.isNotEmpty;
 import static org.apache.maven.shared.utils.StringUtils.split;
+import static org.apache.maven.surefire.booter.SystemUtils.endsWithJavaPath;
+import static org.apache.maven.surefire.booter.SystemUtils.isJava9AtLeast;
+import static org.apache.maven.surefire.booter.SystemUtils.toJdkHomeFromJvmExec;
+import static org.apache.maven.surefire.booter.SystemUtils.toJdkVersionFromReleaseFile;
 import static org.apache.maven.surefire.suite.RunResult.failure;
 import static org.apache.maven.surefire.suite.RunResult.noTestsRun;
 import static org.apache.maven.surefire.util.ReflectionUtils.invokeGetter;
@@ -123,6 +132,10 @@ public abstract class AbstractSurefireMojo
     extends AbstractMojo
     implements SurefireExecutionParameters
 {
+    private static final Map<String, String> JAVA_9_MATCHER_OLD_NOTATION = singletonMap( "version", "[1.9,)" );
+
+    private static final Map<String, String> JAVA_9_MATCHER = singletonMap( "version", "[9,)" );
+
     private static final Platform PLATFORM = new Platform();
 
     private static final File SYSTEM_TMP_DIR = new File( System.getProperty( "java.io.tmpdir" ) );
@@ -895,7 +908,7 @@ public abstract class AbstractSurefireMojo
             getConsoleLogger().info( "Toolchain in maven-" + getPluginName() + "-plugin: " + toolchain );
             if ( jvmToUse != null )
             {
-                getConsoleLogger().warning( "Toolchains are ignored, 'executable' parameter is set to " + jvmToUse );
+                getConsoleLogger().warning( "Toolchains are ignored, 'jvm' parameter is set to " + jvmToUse );
             }
         }
 
@@ -1947,7 +1960,7 @@ public abstract class AbstractSurefireMojo
                                                     startupReportConfiguration, consoleLogger );
     }
 
-    protected ForkConfiguration getForkConfiguration()
+    private ForkConfiguration getForkConfiguration() throws MojoFailureException
     {
         File tmpDir = getSurefireTempDir();
 
@@ -2038,24 +2051,59 @@ public abstract class AbstractSurefireMojo
         return debugForkedProcess;
     }
 
-    private String getEffectiveJvm()
+    private JdkAttributes getEffectiveJvm() throws MojoFailureException
     {
-        String jvmToUse = getJvm();
-        if ( toolchain != null && jvmToUse == null )
+        if ( isNotEmpty( jvm ) )
         {
-            jvmToUse = toolchain.findTool( "java" ); //NOI18N
+            File pathToJava = new File( jvm ).getAbsoluteFile();
+            if ( !endsWithJavaPath( pathToJava.getPath() ) )
+            {
+                throw new MojoFailureException( "Given path does not end with java executor \""
+                                                        + pathToJava.getPath() + "\"." );
+            }
+
+            if ( !( pathToJava.isFile()
+                            || "java".equals( pathToJava.getName() ) && pathToJava.getParentFile().isDirectory() ) )
+            {
+                throw new MojoFailureException( "Given path to java executor does not exist \""
+                                                        + pathToJava.getPath() + "\"." );
+            }
+
+            File jdkHome = toJdkHomeFromJvmExec( pathToJava.getPath() );
+            Double version = jdkHome == null ? null : toJdkVersionFromReleaseFile( jdkHome );
+            boolean javaVersion9 = version == null ? isJava9AtLeast( pathToJava.getPath() ) : isJava9AtLeast( version );
+            return new JdkAttributes( pathToJava.getPath(), javaVersion9 );
         }
 
-        if ( isEmpty( jvmToUse ) )
+        if ( toolchain != null )
         {
-            // use the same JVM as the one used to run Maven (the "java.home" one)
-            jvmToUse = System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + "java";
-            getConsoleLogger().debug( "Using JVM: " + jvmToUse );
+            String jvmToUse = toolchain.findTool( "java" );
+            if ( isNotEmpty( jvmToUse ) )
+            {
+                boolean javaVersion9 = false;
+
+                if ( toolchain instanceof DefaultToolchain )
+                {
+                    DefaultToolchain defaultToolchain = (DefaultToolchain) toolchain;
+                    javaVersion9 = defaultToolchain.matchesRequirements( JAVA_9_MATCHER )
+                                             || defaultToolchain.matchesRequirements( JAVA_9_MATCHER_OLD_NOTATION );
+                }
+
+                if ( !javaVersion9 )
+                {
+                    javaVersion9 = isJava9AtLeast( jvmToUse );
+                }
+
+                return new JdkAttributes( jvmToUse, javaVersion9 );
+            }
         }
 
-        return jvmToUse;
-    }
+        // use the same JVM as the one used to run Maven (the "java.home" one)
+        String jvmToUse = System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + "java";
+        getConsoleLogger().debug( "Using JVM: " + jvmToUse + " with Java version " + JAVA_RECENT.toString() );
 
+        return new JdkAttributes( jvmToUse, isJavaVersionAtLeast( JAVA_9 ) );
+    }
 
     private Artifact getSurefireBooterArtifact()
     {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
new file mode 100644
index 0000000..65b1254
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/JdkAttributes.java
@@ -0,0 +1,48 @@
+package org.apache.maven.plugin.surefire;
+
+/*
+ * 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 static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
+
+/**
+ * @author <a href="mailto:[hidden email]">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public final class JdkAttributes
+{
+    private final String jvmExecutable;
+    private final boolean java9AtLeast;
+
+    public JdkAttributes( String jvmExecutable, boolean java9AtLeast )
+    {
+        this.jvmExecutable = requireNonNull( jvmExecutable, "null path to java executable" );
+        this.java9AtLeast = java9AtLeast;
+    }
+
+    public String getJvmExecutable()
+    {
+        return jvmExecutable;
+    }
+
+    public boolean isJava9AtLeast()
+    {
+        return java9AtLeast;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
index 1c7626e..b3b9251 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
@@ -20,9 +20,9 @@ package org.apache.maven.plugin.surefire.booterclient;
  */
 
 import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
+import org.apache.maven.plugin.surefire.JdkAttributes;
 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
 import org.apache.maven.plugin.surefire.util.Relocator;
-import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.surefire.booter.Classpath;
 import org.apache.maven.surefire.booter.ForkedBooter;
 import org.apache.maven.surefire.booter.StartupConfiguration;
@@ -42,6 +42,7 @@ import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
 
 import static org.apache.maven.plugin.surefire.SurefireHelper.escapeToPlatformPath;
+import static org.apache.maven.shared.utils.StringUtils.join;
 
 /**
  * Configuration for forking tests.
@@ -66,7 +67,7 @@ public class ForkConfiguration
 
     private final Classpath bootClasspathConfiguration;
 
-    private final String jvmExecutable;
+    private final JdkAttributes jdk;
 
     private final Properties modelProperties;
 
@@ -86,14 +87,14 @@ public class ForkConfiguration
 
     @SuppressWarnings( "checkstyle:parameternumber" )
     public ForkConfiguration( Classpath bootClasspathConfiguration, File tmpDir, String debugLine,
-                              String jvmExecutable, File workingDirectory, Properties modelProperties, String argLine,
+                              JdkAttributes jdk, File workingDirectory, Properties modelProperties, String argLine,
                               Map<String, String> environmentVariables, boolean debugEnabled, int forkCount,
                               boolean reuseForks, Platform pluginPlatform )
     {
         this.bootClasspathConfiguration = bootClasspathConfiguration;
         this.tempDirectory = tmpDir;
         this.debugLine = debugLine;
-        this.jvmExecutable = jvmExecutable;
+        this.jdk = jdk;
         this.workingDirectory = workingDirectory;
         this.modelProperties = modelProperties;
         this.argLine = argLine;
@@ -131,24 +132,25 @@ public class ForkConfiguration
     }
 
     /**
-     * @param classPath            cla the classpath arguments
-     * @param startupConfiguration The startup configuration
+     * @param classPath            cli the classpath arguments
+     * @param config               The startup configuration
      * @param threadNumber         the thread number, to be the replacement in the argLine   @return A commandline
      * @return CommandLine able to flush entire command going to be sent to forked JVM
      * @throws org.apache.maven.surefire.booter.SurefireBooterForkException
      *          when unable to perform the fork
      */
-    public OutputStreamFlushableCommandline createCommandLine( List<String> classPath,
-                                                               StartupConfiguration startupConfiguration,
+    public OutputStreamFlushableCommandline createCommandLine( List<String> classPath, StartupConfiguration config,
                                                                int threadNumber )
-        throws SurefireBooterForkException
+            throws SurefireBooterForkException
     {
-        return createCommandLine( classPath,
-                                  startupConfiguration.getClassLoaderConfiguration()
-                                      .isManifestOnlyJarRequestedAndUsable(),
-                                  startupConfiguration.isShadefire(), startupConfiguration.isProviderMainClass()
-            ? startupConfiguration.getActualClassName()
-            : ForkedBooter.class.getName(), threadNumber );
+        boolean useJar = config.getClassLoaderConfiguration().isManifestOnlyJarRequestedAndUsable();
+
+        boolean shadefire = config.isShadefire();
+
+        String providerThatHasMainMethod =
+                config.isProviderMainClass() ? config.getActualClassName() : ForkedBooter.class.getName();
+
+        return createCommandLine( classPath, useJar, shadefire, providerThatHasMainMethod, threadNumber );
     }
 
     OutputStreamFlushableCommandline createCommandLine( List<String> classPath, boolean useJar, boolean shadefire,
@@ -157,13 +159,26 @@ public class ForkConfiguration
     {
         OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
 
-        cli.setExecutable( jvmExecutable );
+        cli.setExecutable( jdk.getJvmExecutable() );
+
+        String jvmArgLine =
+                replaceThreadNumberPlaceholder( stripNewLines( replacePropertyExpressions() ), threadNumber );
+
+        if ( jdk.isJava9AtLeast() && !jvmArgLine.contains( "--add-modules" ) )
+        {
+            if ( jvmArgLine.isEmpty() )
+            {
+                jvmArgLine = "--add-modules ALL-SYSTEM";
+            }
+            else
+            {
+                jvmArgLine = "--add-modules ALL-SYSTEM " + jvmArgLine;
+            }
+        }
 
-        if ( argLine != null )
+        if ( !jvmArgLine.isEmpty() )
         {
-            cli.createArg().setLine(
-                   replaceThreadNumberPlaceholder( stripNewLines( replacePropertyExpressions( argLine ) ),
-                                                   threadNumber ) );
+            cli.createArg().setLine( jvmArgLine );
         }
 
         for ( Map.Entry<String, String> entry : environmentVariables.entrySet() )
@@ -192,7 +207,7 @@ public class ForkConfiguration
         }
         else
         {
-            cli.addEnvironment( "CLASSPATH", StringUtils.join( classPath.iterator(), File.pathSeparator ) );
+            cli.addEnvironment( "CLASSPATH", join( classPath.iterator(), File.pathSeparator ) );
 
             final String forkedBooter =
                 providerThatHasMainMethod != null ? providerThatHasMainMethod : ForkedBooter.class.getName();
@@ -235,11 +250,18 @@ public class ForkConfiguration
      *
      * This allows other plugins to modify or set properties with the changes getting picked up by surefire.
      */
-    private String replacePropertyExpressions( String argLine )
+    private String replacePropertyExpressions()
     {
         if ( argLine == null )
         {
-            return null;
+            return "";
+        }
+
+        String resolvedArgLine = argLine.trim();
+
+        if ( resolvedArgLine.isEmpty() )
+        {
+            return "";
         }
 
         for ( final String key : modelProperties.stringPropertyNames() )
@@ -247,11 +269,11 @@ public class ForkConfiguration
             String field = "@{" + key + "}";
             if ( argLine.contains( field ) )
             {
-                argLine = argLine.replace( field, modelProperties.getProperty( key, "" ) );
+                resolvedArgLine = resolvedArgLine.replace( field, modelProperties.getProperty( key, "" ) );
             }
         }
 
-        return argLine;
+        return resolvedArgLine;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
index 60c6dfe..629778b 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
@@ -19,7 +19,6 @@ package org.apache.maven.plugin.surefire.report;
  * under the License.
  */
 
-import org.apache.maven.shared.utils.io.IOUtil;
 import org.apache.maven.shared.utils.xml.PrettyPrintXMLWriter;
 import org.apache.maven.shared.utils.xml.XMLWriter;
 import org.apache.maven.surefire.report.ReportEntry;
@@ -42,6 +41,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.StringTokenizer;
 
+import static org.apache.commons.io.IOUtils.closeQuietly;
 import static org.apache.maven.plugin.surefire.report.DefaultReporterFactory.TestResultType;
 import static org.apache.maven.plugin.surefire.report.FileReporterUtils.stripIllegalFilenameChars;
 import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
@@ -239,7 +239,7 @@ public class StatelessXmlReporter
         }
         finally
         {
-            IOUtil.close( fw );
+            closeQuietly( fw );
         }
     }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
index 5d970d8..26b8be7 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
@@ -207,7 +207,7 @@ public class BooterDeserializerProviderConfigurationTest
                                                  boolean readTestsFromInStream )
         throws IOException
     {
-        final ForkConfiguration forkConfiguration = ForkConfigurationTest.getForkConfiguration( null, null );
+        final ForkConfiguration forkConfiguration = ForkConfigurationTest.getForkConfiguration( (String) null );
         PropertiesWrapper props = new PropertiesWrapper( new HashMap<String, String>() );
         BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
         Object test;

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
index 0cb292c..035add0 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
@@ -119,7 +119,7 @@ public class BooterDeserializerStartupConfigurationTest
     private StartupConfiguration saveAndReload( StartupConfiguration startupConfiguration )
         throws IOException
     {
-        final ForkConfiguration forkConfiguration = ForkConfigurationTest.getForkConfiguration( null, null );
+        final ForkConfiguration forkConfiguration = ForkConfigurationTest.getForkConfiguration( (String) null );
         PropertiesWrapper props = new PropertiesWrapper( new HashMap<String, String>() );
         BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
         String aTest = "aTest";

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
index 1e09d6f..b49e164 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
@@ -19,29 +19,32 @@ package org.apache.maven.plugin.surefire.booterclient;
  * under the License.
  */
 
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Properties;
-
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.SystemUtils;
+import org.apache.maven.plugin.surefire.JdkAttributes;
 import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.shared.utils.cli.Commandline;
 import org.apache.maven.surefire.booter.Classpath;
 import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.junit.Test;
 
-import junit.framework.TestCase;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public class ForkConfigurationTest
-    extends TestCase
 {
-
+    @Test
     public void testCreateCommandLine_UseSystemClassLoaderForkOnce_ShouldConstructManifestOnlyJar()
         throws IOException, SurefireBooterForkException
     {
-        ForkConfiguration config = getForkConfiguration( null, "java" );
+        ForkConfiguration config = getForkConfiguration( (String) null );
         File cpElement = getTempClasspathFile();
 
         Commandline cli =
@@ -51,12 +54,13 @@ public class ForkConfigurationTest
         assertTrue( line.contains( "-jar" ) );
     }
 
+    @Test
     public void testArglineWithNewline()
         throws IOException, SurefireBooterForkException
     {
         // SUREFIRE-657
         File cpElement = getTempClasspathFile();
-        ForkConfiguration forkConfiguration = getForkConfiguration( "abc\ndef", null );
+        ForkConfiguration forkConfiguration = getForkConfiguration( "abc\ndef" );
 
         final Commandline commandLine =
             forkConfiguration.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), false, false,
@@ -64,18 +68,19 @@ public class ForkConfigurationTest
         assertTrue( commandLine.toString().contains( "abc def" ) );
     }
 
+    @Test
     public void testCurrentWorkingDirectoryPropagationIncludingForkNumberExpansion()
         throws IOException, SurefireBooterForkException
     {
         // SUREFIRE-1136
         File baseDir =
             new File( FileUtils.getTempDirectory(), "SUREFIRE-1136-" + RandomStringUtils.randomAlphabetic( 3 ) );
-        baseDir.mkdirs();
+        assertTrue( baseDir.mkdirs() );
         baseDir.deleteOnExit();
 
         File cwd = new File( baseDir, "fork_${surefire.forkNumber}" );
 
-        ForkConfiguration config = getForkConfiguration( null, "java", cwd.getCanonicalFile() );
+        ForkConfiguration config = getForkConfiguration( null, cwd.getCanonicalFile() );
         Commandline commandLine = config.createCommandLine( Collections.<String>emptyList(), true, false, null, 1 );
 
         File forkDirectory = new File( baseDir, "fork_1" );
@@ -84,20 +89,21 @@ public class ForkConfigurationTest
             commandLine.getShell().getWorkingDirectory().getCanonicalPath() ) );
     }
 
+    @Test
     public void testExceptionWhenCurrentDirectoryIsNotRealDirectory()
         throws IOException, SurefireBooterForkException
     {
         // SUREFIRE-1136
         File baseDir =
             new File( FileUtils.getTempDirectory(), "SUREFIRE-1136-" + RandomStringUtils.randomAlphabetic( 3 ) );
-        baseDir.mkdirs();
+        assertTrue( baseDir.mkdirs() );
         baseDir.deleteOnExit();
 
         File cwd = new File( baseDir, "cwd.txt" );
         FileUtils.touch( cwd );
         cwd.deleteOnExit();
 
-        ForkConfiguration config = getForkConfiguration( null, "java", cwd.getCanonicalFile() );
+        ForkConfiguration config = getForkConfiguration( null, cwd.getCanonicalFile() );
 
         try
         {
@@ -114,19 +120,20 @@ public class ForkConfigurationTest
         fail();
     }
 
+    @Test
     public void testExceptionWhenCurrentDirectoryCannotBeCreated()
         throws IOException, SurefireBooterForkException
     {
         // SUREFIRE-1136
         File baseDir =
             new File( FileUtils.getTempDirectory(), "SUREFIRE-1136-" + RandomStringUtils.randomAlphabetic( 3 ) );
-        baseDir.mkdirs();
+        assertTrue( baseDir.mkdirs() );
         baseDir.deleteOnExit();
 
         // NULL is invalid for JDK starting from 1.7.60 - https://github.com/openjdk-mirror/jdk/commit/e5389115f3634d25d101e2dcc71f120d4fd9f72f
         // ? character is invalid on Windows, seems to be imposable to create invalid directory using Java on Linux
         File cwd = new File( baseDir, "?\u0000InvalidDirectoryName" );
-        ForkConfiguration config = getForkConfiguration( null, "java", cwd.getAbsoluteFile() );
+        ForkConfiguration config = getForkConfiguration( null, cwd.getAbsoluteFile() );
 
         try
         {
@@ -152,17 +159,31 @@ public class ForkConfigurationTest
         return cpElement;
     }
 
-    public static ForkConfiguration getForkConfiguration( String argLine, String jvm )
+    public static ForkConfiguration getForkConfiguration( File javaExec )
+            throws IOException
+    {
+        return getForkConfiguration( null, javaExec.getAbsolutePath(), new File( "." ).getCanonicalFile() );
+    }
+
+    public static ForkConfiguration getForkConfiguration( String argLine )
         throws IOException
     {
-        return getForkConfiguration( argLine, jvm, new File( "." ).getCanonicalFile() );
+        File jvm = new File( new File( System.getProperty( "java.home" ), "bin" ), "java" );
+        return getForkConfiguration( argLine, jvm.getAbsolutePath(), new File( "." ).getCanonicalFile() );
+    }
+
+    public static ForkConfiguration getForkConfiguration( String argLine, File cwd )
+            throws IOException
+    {
+        File jvm = new File( new File( System.getProperty( "java.home" ), "bin" ), "java" );
+        return getForkConfiguration( argLine, jvm.getAbsolutePath(), cwd );
     }
 
-    public static ForkConfiguration getForkConfiguration( String argLine, String jvm, File cwd )
+    private static ForkConfiguration getForkConfiguration( String argLine, String jvm, File cwd )
         throws IOException
     {
-        return new ForkConfiguration( Classpath.emptyClasspath(), null, null, jvm, cwd, new Properties(), argLine, null,
-                                      false, 1, false, new Platform() );
+        return new ForkConfiguration( Classpath.emptyClasspath(), null, null, new JdkAttributes( jvm, false ),
+                                            cwd, new Properties(), argLine, null, false, 1, false, new Platform() );
     }
 
     // based on http://stackoverflow.com/questions/2591083/getting-version-of-java-in-runtime
@@ -170,6 +191,6 @@ public class ForkConfigurationTest
     {
         String[] javaVersionElements = System.getProperty( "java.runtime.version" ).split( "\\.|_|-b" );
         return Integer.valueOf( javaVersionElements[1] ) >= major
-            && Integer.valueOf( javaVersionElements[4] ) >= update;
+            && Integer.valueOf( javaVersionElements[3] ) >= update;
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6ba5602..a997605 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,7 +97,7 @@
     <maven.surefire.scm.devConnection>scm:git:https://git-wip-us.apache.org/repos/asf/maven-surefire.git</maven.surefire.scm.devConnection>
     <maven.site.path>surefire-archives/surefire-LATEST</maven.site.path>
     <!-- Override with Jigsaw JRE 9 -->
-    <test.jre>${java.home}/..</test.jre>
+    <jdk.home>${java.home}/..</jdk.home>
   </properties>
 
   <dependencyManagement>
@@ -245,6 +245,22 @@
         </exclusions>
       </dependency>
       <dependency>
+        <groupId>org.powermock</groupId>
+        <artifactId>powermock-mockito-release-full</artifactId>
+        <version>1.6.4</version>
+        <classifier>full</classifier>
+        <exclusions>
+          <exclusion>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-core</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
@@ -399,12 +415,12 @@
         </plugin>
         <plugin>
           <artifactId>maven-invoker-plugin</artifactId>
-          <version>2.0.0</version>
+          <version>3.0.1</version>
         </plugin>
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.7.8</version>
+          <version>0.7.9</version>
           <configuration>
             <includes>
               <include>**/failsafe/*</include>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-api/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-api/pom.xml b/surefire-api/pom.xml
index ec5c664..7b29c6d 100644
--- a/surefire-api/pom.xml
+++ b/surefire-api/pom.xml
@@ -52,7 +52,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <jvm>${test.jre}/bin/java</jvm>
+          <jvm>${jdk.home}/bin/java</jvm>
           <redirectTestOutputToFile>true</redirectTestOutputToFile>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-booter/pom.xml b/surefire-booter/pom.xml
index 8fdaf7e..b564fa4 100644
--- a/surefire-booter/pom.xml
+++ b/surefire-booter/pom.xml
@@ -55,6 +55,12 @@
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-mockito-release-full</artifactId>
+      <classifier>full</classifier>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -85,7 +91,7 @@
           </dependency>
         </dependencies>
         <configuration>
-          <jvm>${test.jre}/bin/java</jvm>
+          <jvm>${jdk.home}/bin/java</jvm>
           <redirectTestOutputToFile>true</redirectTestOutputToFile>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java
----------------------------------------------------------------------
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java
index ccdb6e6..3a53ddf 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java
@@ -22,19 +22,29 @@ package org.apache.maven.surefire.booter;
 import org.apache.maven.surefire.util.ReflectionUtils;
 
 import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.management.ManagementFactory;
 import java.lang.reflect.Method;
+import java.util.Properties;
+import java.util.StringTokenizer;
 
 import static java.lang.Thread.currentThread;
+import static org.apache.commons.io.IOUtils.closeQuietly;
 import static org.apache.commons.lang3.JavaVersion.JAVA_9;
 import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT;
+import static org.apache.commons.lang3.StringUtils.isNumeric;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_FREE_BSD;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_NET_BSD;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_OPEN_BSD;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
 import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodChain;
 import static org.apache.maven.surefire.util.ReflectionUtils.tryLoadClass;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
 
 /**
  * JDK 9 support.
@@ -44,13 +54,144 @@ import static org.apache.maven.surefire.util.ReflectionUtils.tryLoadClass;
  */
 public final class SystemUtils
 {
+    private static final double JIGSAW_JAVA_VERSION = 9.0d;
+
     private static final int PROC_STATUS_PID_FIRST_CHARS = 20;
 
-    public SystemUtils()
+    private SystemUtils()
     {
         throw new IllegalStateException( "no instantiable constructor" );
     }
 
+    /**
+     * @param jvmExecPath    e.g. /jdk/bin/java, /jdk/jre/bin/java
+     * @return {@code true} if {@code jvmExecPath} is path to java binary executor
+     */
+    public static boolean endsWithJavaPath( String jvmExecPath )
+    {
+        File javaExec = new File( jvmExecPath ).getAbsoluteFile();
+        File bin = javaExec.getParentFile();
+        String exec = javaExec.getName();
+        return exec.startsWith( "java" ) && bin != null && bin.getName().equals( "bin" );
+    }
+
+    /**
+     * If {@code jvmExecutable} is <tt>/jdk/bin/java</tt> (since jdk9) or <tt>/jdk/jre/bin/java</tt> (prior to jdk9)
+     * then the absolute path to JDK home is returned <tt>/jdk</tt>.
+     * <br>
+     * Null is returned if {@code jvmExecutable} is incorrect.
+     *
+     * @param jvmExecutable    /jdk/bin/java* or /jdk/jre/bin/java*
+     * @return path to jdk directory; or <tt>null</tt> if wrong path or directory layout of JDK installation.
+     */
+    public static File toJdkHomeFromJvmExec( String jvmExecutable )
+    {
+        File bin = new File( jvmExecutable ).getAbsoluteFile().getParentFile();
+        if ( "bin".equals( bin.getName() ) )
+        {
+            File parent = bin.getParentFile();
+            if ( "jre".equals( parent.getName() ) )
+            {
+                File jdk = parent.getParentFile();
+                return new File( jdk, "bin" ).isDirectory() ? jdk : null;
+            }
+            return parent;
+        }
+        return null;
+    }
+
+    /**
+     * If system property <tt>java.home</tt> is <tt>/jdk</tt> (since jdk9) or <tt>/jdk/jre</tt> (prior to jdk9) then
+     * the absolute path to
+     * JDK home is returned <tt>/jdk</tt>.
+     *
+     * @return path to JDK
+     */
+    public static File toJdkHomeFromJre()
+    {
+        return toJdkHomeFromJre( System.getProperty( "java.home" ) );
+    }
+
+    /**
+     * If {@code jreHome} is <tt>/jdk</tt> (since jdk9) or <tt>/jdk/jre</tt> (prior to jdk9) then
+     * the absolute path to JDK home is returned <tt>/jdk</tt>.
+     * <br>
+     * JRE home directory {@code jreHome} must be taken from system property <tt>java.home</tt>.
+     *
+     * @param jreHome    path to /jdk or /jdk/jre
+     * @return path to JDK
+     */
+    static File toJdkHomeFromJre( String jreHome )
+    {
+        File pathToJreOrJdk = new File( jreHome ).getAbsoluteFile();
+        return "jre".equals( pathToJreOrJdk.getName() ) ? pathToJreOrJdk.getParentFile() : pathToJreOrJdk;
+    }
+
+    public static Double toJdkVersionFromReleaseFile( File jdkHome )
+    {
+        File release = new File( requireNonNull( jdkHome ).getAbsoluteFile(), "release" );
+        if ( !release.isFile() )
+        {
+            return null;
+        }
+        InputStream is = null;
+        try
+        {
+            Properties properties = new Properties();
+            is = new FileInputStream( release );
+            properties.load( is );
+            String javaVersion = properties.getProperty( "JAVA_VERSION" ).replace( "\"", "" );
+            StringTokenizer versions = new StringTokenizer( javaVersion, "._" );
+
+            if ( versions.countTokens() == 1 )
+            {
+                javaVersion = versions.nextToken();
+            }
+            else if ( versions.countTokens() >= 2 )
+            {
+                String majorVersion = versions.nextToken();
+                String minorVersion = versions.nextToken();
+                javaVersion = isNumeric( minorVersion ) ? majorVersion + "." + minorVersion : majorVersion;
+            }
+            else
+            {
+                return null;
+            }
+
+            return Double.valueOf( javaVersion );
+        }
+        catch ( IOException e )
+        {
+            return null;
+        }
+        finally
+        {
+            closeQuietly( is );
+        }
+    }
+
+    public static boolean isJava9AtLeast( String jvmExecutablePath )
+    {
+        File externalJavaHome = toJdkHomeFromJvmExec( jvmExecutablePath );
+        File thisJavaHome = toJdkHomeFromJre();
+        if ( thisJavaHome.equals( externalJavaHome ) )
+        {
+            return isBuiltInJava9AtLeast();
+        }
+        Double releaseFileVersion = externalJavaHome == null ? null : toJdkVersionFromReleaseFile( externalJavaHome );
+        return SystemUtils.isJava9AtLeast( releaseFileVersion );
+    }
+
+    static boolean isBuiltInJava9AtLeast()
+    {
+        return isJavaVersionAtLeast( JAVA_9 );
+    }
+
+    public static boolean isJava9AtLeast( Double version )
+    {
+        return version != null && version >= JIGSAW_JAVA_VERSION;
+    }
+
     public static ClassLoader platformClassLoader()
     {
         if ( JAVA_RECENT.atLeast( JAVA_9 ) )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
----------------------------------------------------------------------
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
index 12aff99..1917cbb 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
@@ -19,10 +19,19 @@ package org.apache.maven.surefire.booter;
  * under the License.
  */
 
+import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 
+import java.io.File;
+import java.io.IOException;
 import java.lang.management.ManagementFactory;
 
+import static java.io.File.separator;
 import static org.apache.commons.lang3.JavaVersion.JAVA_9;
 import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_FREE_BSD;
@@ -30,7 +39,14 @@ import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_NET_BSD;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_OPEN_BSD;
 import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyDouble;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.verifyStatic;
 
 /**
  * Test of {@link SystemUtils}.
@@ -38,94 +54,280 @@ import static org.junit.Assume.assumeTrue;
  * @author <a href="mailto:[hidden email]">Tibor Digana (tibor17)</a>
  * @since 2.20.1
  */
+@RunWith( Enclosed.class )
 public class SystemUtilsTest
 {
-    @Test
-    public void shouldBePlatformClassLoader()
+    public static class PlainUnitTests
     {
-        ClassLoader cl = SystemUtils.platformClassLoader();
-        if ( JAVA_RECENT.atLeast( JAVA_9 ) )
+
+        @Test
+        public void shouldParseProprietaryReleaseFile() throws IOException
+        {
+            String classes = new File( "." ).getCanonicalPath() + separator + "target" + separator + "test-classes";
+
+            File path = new File( classes, "jdk8-IBM" + separator + "bin" + separator + "java" );
+            assertThat( SystemUtils.isJava9AtLeast( path.getAbsolutePath() ) ).isFalse();
+
+            path = new File( classes, "jdk8-oracle" + separator + "bin" + separator + "java" );
+            assertThat( SystemUtils.isJava9AtLeast( path.getAbsolutePath() ) ).isFalse();
+
+            path = new File( classes, "jdk9-oracle" + separator + "bin" + separator + "java" );
+            assertThat( SystemUtils.isJava9AtLeast( path.getAbsolutePath() ) ).isTrue();
+        }
+
+        @Test
+        public void incorrectJdkPath() throws IOException
+        {
+            File jre = new File( System.getProperty( "java.home" ) );
+            File jdk = jre.getParentFile();
+            File incorrect = jdk.getParentFile();
+            assertThat( SystemUtils.isJava9AtLeast( incorrect.getAbsolutePath() ) ).isFalse();
+        }
+
+        @Test
+        public void shouldHaveJavaPath()
+        {
+            String javaPath = System.getProperty( "java.home" ) + separator + "bin" + separator + "java";
+            assertThat( SystemUtils.endsWithJavaPath( javaPath ) ).isTrue();
+        }
+
+        @Test
+        public void shouldNotHaveJavaPath()
+        {
+            assertThat( SystemUtils.endsWithJavaPath( "/jdk" ) ).isFalse();
+        }
+
+        @Test
+        public void shouldNotExtractJdkHomeFromJavaExec()
+        {
+            File pathToJdk = SystemUtils.toJdkHomeFromJvmExec( "/jdk/binx/java" );
+            assertThat( pathToJdk ).isNull();
+        }
+
+        @Test
+        public void shouldExtractJdkHomeFromJavaExec()
+        {
+            File pathToJdk = SystemUtils.toJdkHomeFromJvmExec( "/jdk/bin/java" );
+            assertThat( pathToJdk ).isEqualTo( new File( "/jdk" ).getAbsoluteFile() );
+        }
+
+        @Test
+        public void shouldNotExtractJdkHomeFromJreExec() throws IOException
+        {
+            String classes = new File( "." ).getCanonicalPath() + separator + "target" + separator + "test-classes";
+            File jdk = new File( classes, "jdk" );
+            String pathToJreExec = jdk.getAbsolutePath() + separator + "jre" + separator + "binx" + separator + "java";
+            File pathToJdk = SystemUtils.toJdkHomeFromJvmExec( pathToJreExec );
+            assertThat( pathToJdk ).isNull();
+        }
+
+        @Test
+        public void shouldExtractJdkHomeFromJreExec() throws IOException
+        {
+            String classes = new File( "." ).getCanonicalPath() + separator + "target" + separator + "test-classes";
+            File jdk = new File( classes, "jdk" );
+            String pathToJreExec = jdk.getAbsolutePath() + separator + "jre" + separator + "bin" + separator + "java";
+            File pathToJdk = SystemUtils.toJdkHomeFromJvmExec( pathToJreExec );
+            assertThat( pathToJdk ).isEqualTo( jdk );
+        }
+
+        @Test
+        public void shouldExtractJdkHomeFromJre()
+        {
+            File pathToJdk = SystemUtils.toJdkHomeFromJre( "/jdk/jre" );
+            assertThat( pathToJdk ).isEqualTo( new File( "/jdk" ).getAbsoluteFile() );
+        }
+
+        @Test
+        public void shouldExtractJdkHomeFromJdk()
         {
-            assertThat( cl ).isNotNull();
+            File pathToJdk = SystemUtils.toJdkHomeFromJre( "/jdk/" );
+            assertThat( pathToJdk ).isEqualTo( new File( "/jdk" ).getAbsoluteFile() );
         }
-        else
+
+        @Test
+        public void shouldExtractJdkHomeFromRealPath()
         {
+            File pathToJdk = SystemUtils.toJdkHomeFromJre();
+
+            if ( JAVA_RECENT.atLeast( JAVA_9 ) )
+            {
+                File realJdkHome = new File( System.getProperty( "java.home" ) ).getAbsoluteFile();
+                assertThat( realJdkHome ).isDirectory();
+                assertThat( realJdkHome.getName() ).isNotEqualTo( "jre" );
+                assertThat( pathToJdk ).isEqualTo( realJdkHome );
+            }
+            else
+            {
+                File realJreHome = new File( System.getProperty( "java.home" ) ).getAbsoluteFile();
+                assertThat( realJreHome ).isDirectory();
+                assertThat( realJreHome.getName() ).isEqualTo( "jre" );
+                File realJdkHome = realJreHome.getParentFile();
+                assertThat( pathToJdk ).isEqualTo( realJdkHome );
+            }
+        }
+
+        @Test
+        public void shouldBeJavaVersion()
+        {
+            assertThat( SystemUtils.isJava9AtLeast( (Double) null ) ).isFalse();
+            assertThat( SystemUtils.isJava9AtLeast( 1.8d ) ).isFalse();
+            assertThat( SystemUtils.isJava9AtLeast( 9.0d ) ).isTrue();
+        }
+
+        @Test
+        public void shouldBePlatformClassLoader()
+        {
+            ClassLoader cl = SystemUtils.platformClassLoader();
+            if ( JAVA_RECENT.atLeast( JAVA_9 ) )
+            {
+                assertThat( cl ).isNotNull();
+            }
+            else
+            {
+                assertThat( cl ).isNull();
+            }
+        }
+
+        @Test
+        public void shouldNotFindClassLoader()
+        {
+            ClassLoader cl = SystemUtils.reflectClassLoader( getClass(), "_getPlatformClassLoader_" );
             assertThat( cl ).isNull();
         }
-    }
 
-    @Test
-    public void shouldNotFindClassLoader()
-    {
-        ClassLoader cl = SystemUtils.reflectClassLoader( getClass(), "_getPlatformClassLoader_" );
-        assertThat( cl ).isNull();
-    }
+        @Test
+        public void shouldFindClassLoader()
+        {
+            ClassLoader cl = SystemUtils.reflectClassLoader( getClass(), "getPlatformClassLoader" );
+            assertThat( cl ).isSameAs( ClassLoader.getSystemClassLoader() );
+        }
 
-    @Test
-    public void shouldFindClassLoader()
-    {
-        ClassLoader cl = SystemUtils.reflectClassLoader( getClass(), "getPlatformClassLoader" );
-        assertThat( cl ).isSameAs( ClassLoader.getSystemClassLoader() );
-    }
+        @Test
+        public void shouldBePidOnJigsaw()
+        {
+            assumeTrue( JAVA_RECENT.atLeast( JAVA_9 ) );
 
-    @Test
-    public void shouldBePidOnJigsaw()
-    {
-        assumeTrue( JAVA_RECENT.atLeast( JAVA_9 ) );
+            Long actualPid = SystemUtils.pidOnJava9();
+            String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
 
-        Long actualPid = SystemUtils.pidOnJava9();
-        String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+            assertThat( actualPid + "" )
+                    .isEqualTo( expectedPid );
+        }
 
-        assertThat( actualPid + "" )
-                .isEqualTo( expectedPid );
-    }
+        @Test
+        public void shouldBePidStatusOnLinux() throws Exception
+        {
+            assumeTrue( IS_OS_LINUX );
 
-    @Test
-    public void shouldBePidStatusOnLinux() throws Exception
-    {
-        assumeTrue( IS_OS_LINUX );
+            Long actualPid = SystemUtils.pidStatusOnLinux();
+            String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
 
-        Long actualPid = SystemUtils.pidStatusOnLinux();
-        String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+            assertThat( actualPid + "" )
+                    .isEqualTo( expectedPid );
+        }
 
-        assertThat( actualPid + "" )
-                .isEqualTo( expectedPid );
-    }
+        @Test
+        public void shouldBePidStatusOnBSD() throws Exception
+        {
+            assumeTrue( IS_OS_FREE_BSD || IS_OS_NET_BSD || IS_OS_OPEN_BSD );
 
-    @Test
-    public void shouldBePidStatusOnBSD() throws Exception
-    {
-        assumeTrue( IS_OS_FREE_BSD || IS_OS_NET_BSD || IS_OS_OPEN_BSD );
+            Long actualPid = SystemUtils.pidStatusOnBSD();
+            String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
 
-        Long actualPid = SystemUtils.pidStatusOnBSD();
-        String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+            assertThat( actualPid + "" )
+                    .isEqualTo( expectedPid );
+        }
 
-        assertThat( actualPid + "" )
-                .isEqualTo( expectedPid );
-    }
+        @Test
+        public void shouldBePidOnJMX()
+        {
+            Long actualPid = SystemUtils.pidOnJMX();
+            String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
 
-    @Test
-    public void shouldBePidOnJMX()
-    {
-        Long actualPid = SystemUtils.pidOnJMX();
-        String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+            assertThat( actualPid + "" )
+                    .isEqualTo( expectedPid );
+        }
 
-        assertThat( actualPid + "" )
-                .isEqualTo( expectedPid );
-    }
+        @Test
+        public void shouldBePid()
+        {
+            Long actualPid = SystemUtils.pid();
+            String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
 
-    @Test
-    public void shouldBePid()
-    {
-        Long actualPid = SystemUtils.pid();
-        String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+            assertThat( actualPid + "" )
+                    .isEqualTo( expectedPid );
+        }
+
+        public static ClassLoader getPlatformClassLoader()
+        {
+            return ClassLoader.getSystemClassLoader();
+        }
 
-        assertThat( actualPid + "" )
-                .isEqualTo( expectedPid );
     }
 
-    public static ClassLoader getPlatformClassLoader()
+    @RunWith( PowerMockRunner.class )
+    @PrepareForTest( SystemUtils.class )
+    // todo check PowerMock is compliant with Java 9
+    @Ignore( value = "use this test after issue is fixed https://github.com/powermock/powermock/issues/783")
+    public static class MockTest
     {
-        return ClassLoader.getSystemClassLoader();
+
+        @Test
+        public void shouldBeDifferentJdk9() throws IOException
+        {
+            testIsJava9AtLeast( new File( System.getProperty( "java.home" ) ) );
+        }
+
+        @Test
+        public void shouldBeSameJdk9() throws IOException
+        {
+            assumeFalse( JAVA_RECENT.atLeast( JAVA_9 ) );
+            testIsJava9AtLeast( new File( System.getProperty( "java.home" ) ).getParentFile() );
+        }
+
+        private static void testIsJava9AtLeast( File pathInJdk ) throws IOException
+        {
+            File path = new File( pathInJdk, "bin" + separator + "java" );
+
+            mockStatic( SystemUtils.class );
+
+            when( SystemUtils.isJava9AtLeast( anyString() ) )
+                    .thenCallRealMethod();
+
+            when( SystemUtils.toJdkHomeFromJvmExec( anyString() ) )
+                    .thenCallRealMethod();
+
+            when( SystemUtils.toJdkHomeFromJre() )
+                    .thenCallRealMethod();
+
+            when( SystemUtils.toJdkHomeFromJre( anyString() ) )
+                    .thenCallRealMethod();
+
+            when( SystemUtils.isBuiltInJava9AtLeast() )
+                    .thenCallRealMethod();
+
+            when( SystemUtils.toJdkVersionFromReleaseFile( any( File.class ) ) )
+                    .thenCallRealMethod();
+
+            when( SystemUtils.isJava9AtLeast( anyDouble() ) )
+                    .thenCallRealMethod();
+
+            if ( JAVA_RECENT.atLeast( JAVA_9 ) )
+            {
+                assertThat( SystemUtils.isJava9AtLeast( path.getAbsolutePath() ) ).isTrue();
+            }
+            else
+            {
+                assertThat( SystemUtils.isJava9AtLeast( path.getAbsolutePath() ) ).isFalse();
+            }
+
+            verifyStatic( Mockito.times( 0 ) );
+            SystemUtils.toJdkVersionFromReleaseFile( any( File.class ) );
+
+            verifyStatic( Mockito.times( 1 ) );
+            SystemUtils.isBuiltInJava9AtLeast();
+        }
+
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/src/test/resources/jdk/bin/java
----------------------------------------------------------------------
diff --git a/surefire-booter/src/test/resources/jdk/bin/java b/surefire-booter/src/test/resources/jdk/bin/java
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/src/test/resources/jdk/jre/bin/java
----------------------------------------------------------------------
diff --git a/surefire-booter/src/test/resources/jdk/jre/bin/java b/surefire-booter/src/test/resources/jdk/jre/bin/java
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/src/test/resources/jdk8-IBM/release
----------------------------------------------------------------------
diff --git a/surefire-booter/src/test/resources/jdk8-IBM/release b/surefire-booter/src/test/resources/jdk8-IBM/release
new file mode 100644
index 0000000..f8baa30
--- /dev/null
+++ b/surefire-booter/src/test/resources/jdk8-IBM/release
@@ -0,0 +1 @@
+JAVA_VERSION="1.8.0"

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/src/test/resources/jdk8-oracle/release
----------------------------------------------------------------------
diff --git a/surefire-booter/src/test/resources/jdk8-oracle/release b/surefire-booter/src/test/resources/jdk8-oracle/release
new file mode 100644
index 0000000..567277b
--- /dev/null
+++ b/surefire-booter/src/test/resources/jdk8-oracle/release
@@ -0,0 +1 @@
+JAVA_VERSION="1.8.0_141"

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-booter/src/test/resources/jdk9-oracle/release
----------------------------------------------------------------------
diff --git a/surefire-booter/src/test/resources/jdk9-oracle/release b/surefire-booter/src/test/resources/jdk9-oracle/release
new file mode 100644
index 0000000..afcc747
--- /dev/null
+++ b/surefire-booter/src/test/resources/jdk9-oracle/release
@@ -0,0 +1 @@
+JAVA_VERSION="9"

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-integration-tests/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/pom.xml b/surefire-integration-tests/pom.xml
index d9142de..5f6bae4 100644
--- a/surefire-integration-tests/pom.xml
+++ b/surefire-integration-tests/pom.xml
@@ -100,7 +100,8 @@
           <forkMode>never</forkMode>
           <argLine>${argLine}</argLine>
           <includes>
-            <include>org/apache/**/*IT*.java</include>
+            <include>org/apache/**/Java9FullApiIT.java</include>
+            <include>org/apache/**/Surefire1265Java9IT.java</include>
           </includes>
           <!-- Pass current surefire version to the main suite so that it -->
           <!-- can forward to all integration test projects. SUREFIRE-513 -->
@@ -109,12 +110,15 @@
             <maven.home>${maven.home}</maven.home>
             <maven.settings.file>${project.basedir}/../surefire-setup-integration-tests/target/private/it-settings.xml
             </maven.settings.file>
+            <maven.toolchains.file>${project.basedir}/../surefire-setup-integration-tests/target/private/toolchains.xml
+            </maven.toolchains.file>
             <maven.repo.local>${project.basedir}/../surefire-setup-integration-tests/target/it-repo</maven.repo.local>
             <maven.test.tmpdir>${project.build.directory}</maven.test.tmpdir>
             <user.localRepository>${settings.localRepository}</user.localRepository>
             <useInterpolatedSettings>${useInterpolatedSettings}</useInterpolatedSettings>
             <testBuildDirectory>${project.build.testOutputDirectory}</testBuildDirectory>
             <verifier.forkMode>${verifier.forkMode}</verifier.forkMode>
+            <jdk.home>${jdk.home}</jdk.home>
           </systemPropertyVariables>
           <redirectTestOutputToFile>false</redirectTestOutputToFile>
         </configuration>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractJigsawIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractJigsawIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractJigsawIT.java
new file mode 100644
index 0000000..c2d0173
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractJigsawIT.java
@@ -0,0 +1,113 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * 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 org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+/**
+ * Abstract test class for Jigsaw tests.
+ *
+ * @author <a href="mailto:[hidden email]">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public abstract class AbstractJigsawIT
+        extends SurefireJUnit4IntegrationTestCase
+{
+    protected static final String JDK_HOME_KEY = "jdk.home";
+    protected static final String JDK_HOME = System.getProperty( JDK_HOME_KEY );
+    private static final double JIGSAW_JAVA_VERSION = 9.0d;
+
+    protected abstract String getProjectDirectoryName();
+
+    protected SurefireLauncher assumeJigsaw() throws IOException
+    {
+        assumeTrue( "There's no JDK 9 provided.",
+                          JAVA_RECENT.atLeast( JAVA_9 ) || JDK_HOME != null && isExtJava9AtLeast() );
+        // fail( JDK_HOME_KEY + " was provided with value " + JDK_HOME + " but it is not Jigsaw Java 9." );
+
+        SurefireLauncher launcher = unpack();
+
+        if ( JDK_HOME != null )
+        {
+            launcher.setLauncherJavaHome( JDK_HOME );
+        }
+
+        return launcher;
+    }
+
+    protected SurefireLauncher assumeJava9Property() throws IOException
+    {
+        assumeTrue( "There's no JDK 9 provided.", JDK_HOME != null && isExtJava9AtLeast() );
+        return unpack();
+    }
+
+    private SurefireLauncher unpack()
+    {
+        return unpack( getProjectDirectoryName() );
+    }
+
+    private static boolean isExtJava9AtLeast() throws IOException
+    {
+        File release = new File( JDK_HOME, "release" );
+
+        if ( !release.isFile() )
+        {
+            fail( JDK_HOME_KEY + " was provided with value " + JDK_HOME + " but file does not exist "
+                          + JDK_HOME + File.separator + "release"
+            );
+        }
+
+        Properties properties = new Properties();
+        try ( InputStream is = new FileInputStream( release ) )
+        {
+            properties.load( is );
+        }
+        String javaVersion = properties.getProperty( "JAVA_VERSION" ).replace( "\"", "" );
+        StringTokenizer versions = new StringTokenizer( javaVersion, "._" );
+
+        if ( versions.countTokens() == 1 )
+        {
+            javaVersion = versions.nextToken();
+        }
+        else if ( versions.countTokens() >= 2 )
+        {
+            javaVersion = versions.nextToken() + "." + versions.nextToken();
+        }
+        else
+        {
+            fail( "unexpected java version format" );
+        }
+
+        return Double.valueOf( javaVersion ) >= JIGSAW_JAVA_VERSION;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/Java9FullApiIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/Java9FullApiIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/Java9FullApiIT.java
new file mode 100644
index 0000000..840f65c
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/Java9FullApiIT.java
@@ -0,0 +1,95 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * 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 org.apache.maven.surefire.its.fixture.OutputValidator;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Running Surefire on the top of JDK 9 and should be able to load
+ * classes of multiple different Jigsaw modules without error.
+ *
+ * @author <a href="mailto:[hidden email]">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public class Java9FullApiIT
+        extends AbstractJigsawIT
+{
+
+    @Test
+    public void shouldLoadMultipleJavaModules_JavaHome() throws IOException
+    {
+        OutputValidator validator = assumeJigsaw()
+                                            .setForkJvm()
+                                            .debugLogging()
+                                            .executeTest()
+                                            .verifyErrorFree( 2 );
+
+        validator.verifyTextInLog( "loaded class java.sql.SQLException" )
+                .verifyTextInLog( "loaded class javax.xml.ws.Holder" )
+                .verifyTextInLog( "loaded class javax.xml.bind.JAXBException" )
+                .verifyTextInLog( "loaded class org.omg.CORBA.BAD_INV_ORDER" )
+                .verifyTextInLog( "java.specification.version=9" );
+    }
+
+    @Test
+    public void shouldLoadMultipleJavaModules_JvmParameter() throws IOException
+    {
+        OutputValidator validator = assumeJava9Property()
+                                            .setForkJvm()
+                                            .debugLogging()
+                                            .sysProp( JDK_HOME_KEY, new File( JDK_HOME ).getAbsolutePath() )
+                                            .executeTest()
+                                            .verifyErrorFree( 2 );
+
+        validator.verifyTextInLog( "loaded class java.sql.SQLException" )
+                .verifyTextInLog( "loaded class javax.xml.ws.Holder" )
+                .verifyTextInLog( "loaded class javax.xml.bind.JAXBException" )
+                .verifyTextInLog( "loaded class org.omg.CORBA.BAD_INV_ORDER" )
+                .verifyTextInLog( "java.specification.version=9" );
+    }
+
+    @Test
+    public void shouldLoadMultipleJavaModules_ToolchainsXML() throws IOException
+    {
+        OutputValidator validator = assumeJava9Property()
+                                            .setForkJvm()
+                                            .activateProfile( "use-toolchains" )
+                                            .addGoal( "--toolchains" )
+                                            .addGoal( System.getProperty( "maven.toolchains.file" ) )
+                                            .executeTest()
+                                            .verifyErrorFree( 2 );
+
+        validator.verifyTextInLog( "loaded class java.sql.SQLException" )
+                .verifyTextInLog( "loaded class javax.xml.ws.Holder" )
+                .verifyTextInLog( "loaded class javax.xml.bind.JAXBException" )
+                .verifyTextInLog( "loaded class org.omg.CORBA.BAD_INV_ORDER" )
+                .verifyTextInLog( "java.specification.version=9" );
+    }
+
+    @Override
+    protected String getProjectDirectoryName()
+    {
+        return "java9-full-api";
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1265Java9IT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1265Java9IT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1265Java9IT.java
index 9e06e8e..2e92805 100644
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1265Java9IT.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1265Java9IT.java
@@ -19,11 +19,10 @@ package org.apache.maven.surefire.its.jiras;
  * under the License.
  */
 
-import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
-import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.apache.maven.surefire.its.AbstractJigsawIT;
 import org.junit.Test;
 
-import static org.junit.Assume.assumeTrue;
+import java.io.IOException;
 
 @SuppressWarnings( { "javadoc", "checkstyle:javadoctype" } )
 /**
@@ -40,19 +39,19 @@ import static org.junit.Assume.assumeTrue;
  * @since 2.20.1
  */
 public class Surefire1265Java9IT
-        extends SurefireJUnit4IntegrationTestCase
+        extends AbstractJigsawIT
 {
     @Test
-    public void shouldRunInPluginJava9()
+    public void shouldRunInPluginJava9() throws IOException
     {
-        assumeTrue( System.getProperty( "java.specification.version" ).compareTo( "1.8" ) > 0 );
-        unpack()
+        assumeJigsaw()
                 .executeTest()
                 .verifyErrorFree( 2 );
     }
 
-    private SurefireLauncher unpack()
+    @Override
+    protected String getProjectDirectoryName()
     {
-        return unpack( "/surefire-1265" );
+        return "/surefire-1265";
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-integration-tests/src/test/resources/java9-full-api/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/java9-full-api/pom.xml b/surefire-integration-tests/src/test/resources/java9-full-api/pom.xml
new file mode 100644
index 0000000..4088348
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/java9-full-api/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.maven.surefire</groupId>
+        <artifactId>it-parent</artifactId>
+        <version>1.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>java9-full-api</artifactId>
+
+    <properties>
+        <maven.compiler.source>1.6</maven.compiler.source>
+        <maven.compiler.target>1.6</maven.compiler.target>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <forkMode>once</forkMode>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>use-jvm-config-paramater</id>
+            <activation>
+                <property>
+                    <name>jdk.home</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <jvm>${jdk.home}/bin/java</jvm>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>use-toolchains</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-toolchains-plugin</artifactId>
+                        <version>1.1</version>
+                        <executions>
+                            <execution>
+                                <phase>validate</phase>
+                                <goals>
+                                    <goal>toolchain</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <toolchains>
+                                <jdk>
+                                    <version>9</version>
+                                </jdk>
+                            </toolchains>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9Test.java b/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9Test.java
new file mode 100644
index 0000000..0ee3115
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9Test.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.junit.Test;
+
+public class J9Test
+{
+    @Test
+    public void testMiscellaneousAPI() throws java.sql.SQLException
+    {
+        System.out.println( "loaded class " + java.sql.SQLException.class.getName() );
+        System.out.println( "loaded class " + javax.xml.ws.Holder.class.getName() );
+        System.out.println( "loaded class " + javax.xml.bind.JAXBException.class.getName() );
+        System.out.println( "loaded class " + org.omg.CORBA.BAD_INV_ORDER.class.getName() );
+        System.out.println( "java.specification.version=" + System.getProperty( "java.specification.version" ) );
+    }
+
+    @Test
+    public void test_corba_mod() throws org.omg.CORBA.BAD_INV_ORDER
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-setup-integration-tests/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-setup-integration-tests/pom.xml b/surefire-setup-integration-tests/pom.xml
index fde80ae..429abc4 100644
--- a/surefire-setup-integration-tests/pom.xml
+++ b/surefire-setup-integration-tests/pom.xml
@@ -106,6 +106,23 @@
   </dependencies>
 
   <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <targetPath>${project.build.outputDirectory}</targetPath>
+        <excludes>
+          <exclude>toolchains.xml</exclude>
+        </excludes>
+      </resource>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <targetPath>${project.build.directory}/private</targetPath>
+        <includes>
+          <include>toolchains.xml</include>
+        </includes>
+      </resource>
+    </resources>
     <plugins>
       <plugin>
         <artifactId>maven-help-plugin</artifactId>
@@ -127,11 +144,9 @@
       <plugin>
         <artifactId>maven-invoker-plugin</artifactId>
         <configuration>
-          <extraArtifacts>
-            <extraArtifact>org.apache.maven.surefire:surefire-testng-utils:${project.version}</extraArtifact>
-          </extraArtifacts>
           <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
           <extraArtifacts>
+            <extraArtifact>org.apache.maven.surefire:surefire-testng-utils:${project.version}</extraArtifact>
             <extraArtifact>org.testng:testng:4.7:jar:jdk15</extraArtifact>
             <extraArtifact>org.testng:testng:5.0.2:jar:jdk15</extraArtifact>
             <extraArtifact>org.testng:testng:5.1:jar:jdk15</extraArtifact>
@@ -173,6 +188,7 @@
             <extraArtifact>junit:junit:4.8.1</extraArtifact>
             <extraArtifact>junit:junit:4.8.2</extraArtifact>
             <extraArtifact>junit:junit:4.11</extraArtifact>
+            <extraArtifact>junit:junit:4.12</extraArtifact>
             <extraArtifact>junit:junit-dep:4.8</extraArtifact>
             <extraArtifact>junit:junit-dep:4.7</extraArtifact>
             <extraArtifact>junit:junit-dep:4.4</extraArtifact>
@@ -184,7 +200,11 @@
             <extraArtifact>org.codehaus.plexus:plexus-utils:1.5.8</extraArtifact>
             <extraArtifact>org.codehaus.plexus:plexus-utils:1.5.15</extraArtifact>
             <extraArtifact>org.mockito:mockito-core:1.8.5</extraArtifact>
+            <extraArtifact>org.powermock:powermock-mockito-release-full:1.6.4:jar:full</extraArtifact>
             <extraArtifact>org.codehaus.plexus:plexus-interpolation:1.12</extraArtifact>
+            <extraArtifact>org.hamcrest:hamcrest-core:1.3</extraArtifact>
+            <extraArtifact>org.hamcrest:hamcrest-library:1.3</extraArtifact>
+            <extraArtifact>org.easytesting:fest-assert:1.4</extraArtifact>
           </extraArtifacts>
         </configuration>
         <executions>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/1922adaf/surefire-setup-integration-tests/src/main/resources/toolchains.xml
----------------------------------------------------------------------
diff --git a/surefire-setup-integration-tests/src/main/resources/toolchains.xml b/surefire-setup-integration-tests/src/main/resources/toolchains.xml
new file mode 100644
index 0000000..f9f1d66
--- /dev/null
+++ b/surefire-setup-integration-tests/src/main/resources/toolchains.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<toolchains xmlns="http://maven.apache.org/POM/4.0.0"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd">
+    <toolchain>
+        <type>jdk</type>
+        <provides>
+            <id>jdk9</id>
+            <version>9</version>
+            <vendor>oracle</vendor>
+        </provides>
+        <configuration>
+            <jdkHome>${jdk.home}</jdkHome>
+        </configuration>
+    </toolchain>
+</toolchains>

Loading...