You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2017/08/13 22:21:45 UTC

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

Repository: maven-surefire
Updated Branches:
  refs/heads/SUREFIRE-1403 a8e24ad96 -> e490b265b (forced update)


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/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:tibordigana@apache.org">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/e490b265/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/e490b265/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/e490b265/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/e490b265/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/e490b265/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/e490b265/surefire-integration-tests/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/pom.xml b/surefire-integration-tests/pom.xml
index d9142de..4ea01b4 100644
--- a/surefire-integration-tests/pom.xml
+++ b/surefire-integration-tests/pom.xml
@@ -55,7 +55,6 @@
     <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-settings</artifactId>
-      <version>2.0.6</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -109,12 +108,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/e490b265/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:tibordigana@apache.org">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/e490b265/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..b1bea12
--- /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:tibordigana@apache.org">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()
+                                            .execute( "verify" )
+                                            .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 ).getCanonicalPath() )
+                                            .execute( "verify" )
+                                            .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" ) )
+                                            .execute( "verify" )
+                                            .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/e490b265/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/e490b265/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..7d9026e
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/java9-full-api/pom.xml
@@ -0,0 +1,122 @@
+<?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>
+            <plugin>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <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/e490b265/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9IT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9IT.java b/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9IT.java
new file mode 100644
index 0000000..9daf55d
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9IT.java
@@ -0,0 +1,39 @@
+/*
+ * 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 J9IT
+{
+    @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( "loaded class " + javax.xml.xpath.XPath.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/e490b265/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..6745d5f
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/java9-full-api/src/test/java/J9Test.java
@@ -0,0 +1,39 @@
+/*
+ * 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( "loaded class " + javax.xml.xpath.XPath.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/e490b265/surefire-setup-integration-tests/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-setup-integration-tests/pom.xml b/surefire-setup-integration-tests/pom.xml
index fde80ae..ff2ddbf 100644
--- a/surefire-setup-integration-tests/pom.xml
+++ b/surefire-setup-integration-tests/pom.xml
@@ -89,7 +89,7 @@
     <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-settings</artifactId>
-      <version>2.0.6</version>
+      <version>${mavenVersion}</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -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/e490b265/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>


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

Posted by ti...@apache.org.
[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/e490b265
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/e490b265
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/e490b265

Branch: refs/heads/SUREFIRE-1403
Commit: e490b265b6e9a908f2a83a887657c4f3456b4bcc
Parents: 1a65d61
Author: Tibor17 <ti...@apache.org>
Authored: Mon Aug 7 12:43:17 2017 +0200
Committer: Tibor17 <ti...@apache.org>
Committed: Mon Aug 14 00:21:22 2017 +0200

----------------------------------------------------------------------
 maven-failsafe-plugin/pom.xml                   |  38 +--
 .../plugin/failsafe/IntegrationTestMojo.java    |  32 +-
 .../maven/plugin/failsafe/VerifyMojo.java       |   7 +-
 .../failsafe/util/FailsafeSummaryXmlUtils.java  | 112 +++++--
 .../apache/maven/plugin/failsafe/util/JAXB.java | 104 ------
 .../failsafe/MarshallerUnmarshallerTest.java    |  46 ++-
 .../maven/plugin/failsafe/RunResultTest.java    |  17 +-
 .../maven/plugin/failsafe/failsafe-summary.xml  |   2 +-
 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 ++--
 maven-surefire-plugin/pom.xml                   |  27 +-
 pom.xml                                         |  32 +-
 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              |   4 +-
 .../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   | 122 +++++++
 .../java9-full-api/src/test/java/J9IT.java      |  39 +++
 .../java9-full-api/src/test/java/J9Test.java    |  39 +++
 surefire-setup-integration-tests/pom.xml        |  28 +-
 .../src/main/resources/toolchains.xml           |  35 ++
 36 files changed, 1251 insertions(+), 411 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/pom.xml b/maven-failsafe-plugin/pom.xml
index ec48929..f4b2c09 100644
--- a/maven-failsafe-plugin/pom.xml
+++ b/maven-failsafe-plugin/pom.xml
@@ -66,39 +66,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.cxf</groupId>
-        <artifactId>cxf-xjc-plugin</artifactId>
-        <version>3.1.0</version>
-        <executions>
-          <execution>
-            <id>generate-failsafe-summary</id>
-            <goals>
-              <goal>xsdtojava</goal>
-            </goals>
-            <configuration>
-              <sourceRoot>${project.build.directory}/generated-sources/jaxb</sourceRoot>
-              <xsdOptions>
-                <xsdOption>
-                  <!--
-                  Due to historical reasons and due to both Surefire and Failsafe Plugin have very similar project
-                  pages (mvn site), the Maven Site for both projects is generated upon one common location in
-                  maven-surefire-plugin. The XSD files are located in maven-surefire-plugin project. Do NOT duplicate
-                  the XSD in to maven-failsafe-plugin.
-                  -->
-                  <xsd>../maven-surefire-plugin/src/site/resources/xsd/failsafe-summary.xsd</xsd>
-                  <bindingFile>../maven-surefire-plugin/src/site/resources/xsd/failsafe-summary.xjb</bindingFile>
-                  <packagename>org.apache.maven.plugin.failsafe.xmlsummary</packagename>
-                  <extensionArgs>
-                    <arg>-encoding</arg>
-                    <arg>${project.build.sourceEncoding}</arg>
-                  </extensionArgs>
-                </xsdOption>
-              </xsdOptions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-plugin-plugin</artifactId>
         <configuration>
@@ -211,6 +178,7 @@
               <artifactSet>
                 <includes>
                   <include>org.apache.maven.shared:maven-shared-utils</include>
+                  <include>commons-io:commons-io</include>
                 </includes>
               </artifactSet>
               <relocations>
@@ -218,6 +186,10 @@
                   <pattern>org.apache.maven.shared</pattern>
                   <shadedPattern>org.apache.maven.surefire.shade.org.apache.maven.shared</shadedPattern>
                 </relocation>
+                <relocation>
+                  <pattern>org.apache.commons.io</pattern>
+                  <shadedPattern>org.apache.maven.surefire.shade.org.apache.commons.io</shadedPattern>
+                </relocation>
               </relocations>
             </configuration>
           </execution>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
index 28b2859..723a4a1 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
@@ -27,10 +27,8 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
-import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.surefire.suite.RunResult;
 
-import javax.xml.bind.JAXBException;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
@@ -40,7 +38,6 @@ import java.util.List;
 import java.util.Locale;
 
 import static org.apache.maven.plugin.failsafe.util.FailsafeSummaryXmlUtils.writeSummary;
-import static org.apache.maven.shared.utils.ReaderFactory.FILE_ENCODING;
 
 /**
  * Run integration tests using Surefire.
@@ -258,6 +255,9 @@ public class IntegrationTestMojo
 
     /**
      * The character encoding scheme to be applied.
+     * Deprecated since 2.20.1 and used encoding UTF-8 in <tt>failsafe-summary.xml</tt>.
+     *
+     * @deprecated since of 2.20.1
      */
     @Parameter( property = "encoding", defaultValue = "${project.reporting.outputEncoding}" )
     private String encoding;
@@ -390,13 +390,9 @@ public class IntegrationTestMojo
         try
         {
             Object token = getPluginContext().get( FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
-            writeSummary( summary, summaryFile, token != null, toCharset( getEncodingOrDefault() ) );
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( e.getMessage(), e );
+            writeSummary( summary, summaryFile, token != null );
         }
-        catch ( JAXBException e )
+        catch ( Exception e )
         {
             throw new MojoExecutionException( e.getMessage(), e );
         }
@@ -404,24 +400,6 @@ public class IntegrationTestMojo
         getPluginContext().put( FAILSAFE_IN_PROGRESS_CONTEXT_KEY, FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
     }
 
-    private String getEncodingOrDefault()
-    {
-        if ( StringUtils.isEmpty( encoding ) )
-        {
-            getConsoleLogger()
-                    .warning( "File encoding has not been set, using platform encoding "
-                                      + FILE_ENCODING
-                                      + ", i.e. build is platform dependent! The file encoding for reports output files"
-                                      + " should be provided by the POM property ${project.reporting.outputEncoding}."
-            );
-            return FILE_ENCODING;
-        }
-        else
-        {
-            return encoding;
-        }
-    }
-
     private boolean isJarArtifact( File artifactFile )
     {
         return artifactFile != null && artifactFile.isFile() && artifactFile.getName().toLowerCase().endsWith( ".jar" );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
index 04cc72c..3075a6f 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
@@ -34,7 +34,6 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.surefire.cli.CommandLineOption;
 import org.apache.maven.surefire.suite.RunResult;
 
-import javax.xml.bind.JAXBException;
 import java.io.File;
 import java.util.Collection;
 
@@ -145,7 +144,9 @@ public class VerifyMojo
 
     /**
      * The character encoding scheme to be applied.
+     * Deprecated since 2.20.1 and used encoding UTF-8 in <tt>failsafe-summary.xml</tt>.
      *
+     * @deprecated since of 2.20.1
      * @noinspection UnusedDeclaration
      */
     @Parameter( property = "encoding", defaultValue = "${project.reporting.outputEncoding}" )
@@ -184,7 +185,7 @@ public class VerifyMojo
                     }
                 }
             }
-            catch ( JAXBException e )
+            catch ( Exception e )
             {
                 throw new MojoExecutionException( e.getMessage(), e );
             }
@@ -208,7 +209,7 @@ public class VerifyMojo
         return consoleLogger;
     }
 
-    private RunResult readSummary( File summaryFile ) throws JAXBException
+    private RunResult readSummary( File summaryFile ) throws Exception
     {
         return FailsafeSummaryXmlUtils.toRunResult( summaryFile );
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/FailsafeSummaryXmlUtils.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/FailsafeSummaryXmlUtils.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/FailsafeSummaryXmlUtils.java
index 1f3f64d..91c5fe5 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/FailsafeSummaryXmlUtils.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/FailsafeSummaryXmlUtils.java
@@ -19,16 +19,24 @@ package org.apache.maven.plugin.failsafe.util;
  * under the License.
  */
 
-import org.apache.maven.plugin.failsafe.xmlsummary.ErrorType;
-import org.apache.maven.plugin.failsafe.xmlsummary.FailsafeSummary;
+import org.apache.commons.io.IOUtils;
 import org.apache.maven.surefire.suite.RunResult;
+import org.xml.sax.InputSource;
 
-import javax.xml.bind.JAXBException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathFactory;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.Charset;
+import java.util.Locale;
 
+import static java.lang.Boolean.parseBoolean;
+import static java.lang.Integer.parseInt;
+import static org.apache.commons.lang3.StringEscapeUtils.escapeXml10;
+import static org.apache.commons.lang3.StringEscapeUtils.unescapeXml;
 import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
+import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
 
 /**
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
@@ -36,46 +44,73 @@ import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
  */
 public final class FailsafeSummaryXmlUtils
 {
+    private static final String FAILSAFE_SUMMARY_XML_SCHEMA_LOCATION =
+            "https://maven.apache.org/surefire/maven-surefire-plugin/xsd/failsafe-summary.xsd";
+
+    private static final String FAILSAFE_SUMMARY_XML_NIL_ATTR =
+            " xsi:nil=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
+
+    private static final String FAILSAFE_SUMMARY_XML_TEMPLATE =
+            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                    + "<failsafe-summary xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+                    + " xsi:noNamespaceSchemaLocation=\"" + FAILSAFE_SUMMARY_XML_SCHEMA_LOCATION + "\""
+                    + " result=\"%s\" timeout=\"%s\">\n"
+                    + "    <completed>%d</completed>\n"
+                    + "    <errors>%d</errors>\n"
+                    + "    <failures>%d</failures>\n"
+                    + "    <skipped>%d</skipped>\n"
+                    + "    <failureMessage%s>%s</failureMessage>\n"
+                    + "</failsafe-summary>";
+
     private FailsafeSummaryXmlUtils()
     {
         throw new IllegalStateException( "No instantiable constructor." );
     }
 
-    public static RunResult toRunResult( File failsafeSummaryXml ) throws JAXBException
+    public static RunResult toRunResult( File failsafeSummaryXml ) throws Exception
     {
-        FailsafeSummary failsafeSummary = JAXB.unmarshal( failsafeSummaryXml, FailsafeSummary.class );
-
-        return new RunResult( failsafeSummary.getCompleted(), failsafeSummary.getErrors(),
-                                    failsafeSummary.getFailures(), failsafeSummary.getSkipped(),
-                                    failsafeSummary.getFailureMessage(), failsafeSummary.isTimeout()
+        XPathFactory xpathFactory = XPathFactory.newInstance();
+        XPath xpath = xpathFactory.newXPath();
+        String completed = evaluateXPath( "/failsafe-summary/completed", xpath, failsafeSummaryXml );
+        String errors = evaluateXPath( "/failsafe-summary/errors", xpath, failsafeSummaryXml );
+        String failures = evaluateXPath( "/failsafe-summary/failures", xpath, failsafeSummaryXml );
+        String skipped = evaluateXPath( "/failsafe-summary/skipped", xpath, failsafeSummaryXml );
+        String failureMessage = evaluateXPath( "/failsafe-summary/failureMessage", xpath, failsafeSummaryXml );
+        String timeout = evaluateXPath( "/failsafe-summary/@timeout", xpath, failsafeSummaryXml );
+        return new RunResult( parseInt( completed ), parseInt( errors ), parseInt( failures ), parseInt( skipped ),
+                                    isBlank( failureMessage ) ? null : unescapeXml( failureMessage ),
+                                    parseBoolean( timeout )
         );
     }
 
     public static void fromRunResultToFile( RunResult fromRunResult, File toFailsafeSummaryXml )
-            throws JAXBException, IOException
-    {
-        fromRunResultToFile( fromRunResult, toFailsafeSummaryXml, UTF_8 );
-    }
-
-    public static void fromRunResultToFile( RunResult fromRunResult, File toFailsafeSummaryXml, Charset encoding )
-            throws JAXBException, IOException
+            throws IOException
     {
-        FailsafeSummary summary = new FailsafeSummary();
-        summary.setCompleted( fromRunResult.getCompletedCount() );
-        summary.setFailureMessage( fromRunResult.getFailure() );
-        summary.setErrors( fromRunResult.getErrors() );
-        summary.setFailures( fromRunResult.getFailures() );
-        summary.setSkipped( fromRunResult.getSkipped() );
-        summary.setTimeout( fromRunResult.isTimeout() );
-        Integer errorCode = fromRunResult.getFailsafeCode();
-        summary.setResult( errorCode == null ? null : ErrorType.fromValue( String.valueOf( errorCode ) ) );
+        String failure = fromRunResult.getFailure();
+        String xml = String.format( Locale.ROOT, FAILSAFE_SUMMARY_XML_TEMPLATE,
+                                          fromRunResult.getFailsafeCode(),
+                                          String.valueOf( fromRunResult.isTimeout() ),
+                                          fromRunResult.getCompletedCount(),
+                                          fromRunResult.getErrors(),
+                                          fromRunResult.getFailures(),
+                                          fromRunResult.getSkipped(),
+                                          isBlank( failure ) ? FAILSAFE_SUMMARY_XML_NIL_ATTR : "",
+                                          isBlank( failure ) ? "" : escapeXml10( failure )
+        );
 
-        JAXB.marshal( summary, encoding, toFailsafeSummaryXml );
+        FileOutputStream os = new FileOutputStream( toFailsafeSummaryXml );
+        try
+        {
+            IOUtils.write( xml, os, UTF_8 );
+        }
+        finally
+        {
+            os.close();
+        }
     }
 
-    public static void writeSummary( RunResult mergedSummary, File mergedSummaryFile, boolean inProgress,
-                                     Charset encoding )
-            throws IOException, JAXBException
+    public static void writeSummary( RunResult mergedSummary, File mergedSummaryFile, boolean inProgress )
+            throws Exception
     {
         if ( !mergedSummaryFile.getParentFile().isDirectory() )
         {
@@ -89,6 +124,21 @@ public final class FailsafeSummaryXmlUtils
             mergedSummary = mergedSummary.aggregate( runResult );
         }
 
-        fromRunResultToFile( mergedSummary, mergedSummaryFile, encoding );
+        fromRunResultToFile( mergedSummary, mergedSummaryFile );
+    }
+
+    private static String evaluateXPath( String expression, XPath xpath, File f )
+            throws Exception
+    {
+        FileInputStream is = new FileInputStream( f );
+        try
+        {
+            xpath.reset();
+            return xpath.evaluate( expression, new InputSource( is ) );
+        }
+        finally
+        {
+            is.close();
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/JAXB.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/JAXB.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/JAXB.java
deleted file mode 100644
index ac51292..0000000
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/util/JAXB.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package org.apache.maven.plugin.failsafe.util;
-
-/*
- * 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 javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.PropertyException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.helpers.DefaultValidationEventHandler;
-import javax.xml.namespace.QName;
-import javax.xml.transform.stream.StreamSource;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import static javax.xml.bind.JAXBContext.newInstance;
-import static javax.xml.bind.Marshaller.JAXB_ENCODING;
-import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
-import static javax.xml.bind.Marshaller.JAXB_FRAGMENT;
-
-/**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20
- */
-public final class JAXB
-{
-    private JAXB()
-    {
-        throw new IllegalStateException( "Not instantiated constructor." );
-    }
-
-    public static <T> T unmarshal( File source, Class<T> rootXmlNode ) throws JAXBException
-    {
-        return unmarshal( source, rootXmlNode, Collections.<String, Object>emptyMap() );
-    }
-
-    public static <T> T unmarshal( File source, Class<T> rootXmlNode, Map<String, ?> props )
-            throws JAXBException
-    {
-        Class<?>[] classesToBeBound = { rootXmlNode };
-        JAXBContext ctx = newInstance( classesToBeBound );
-        Unmarshaller unmarshaller = ctx.createUnmarshaller();
-        properties( props, unmarshaller );
-        unmarshaller.setEventHandler( new DefaultValidationEventHandler() );
-        JAXBElement<T> element = unmarshaller.unmarshal( new StreamSource( source ), rootXmlNode );
-        return element.getValue();
-    }
-
-    @SuppressWarnings( "unchecked" )
-    public static <T> void marshal( T bean, Charset encoding, File destination ) throws JAXBException, IOException
-    {
-        Class<T> type = (Class<T>) bean.getClass();
-        JAXBElement<T> rootElement = buildJaxbElement( bean, type );
-        Class<?>[] classesToBeBound = { type };
-        JAXBContext context = newInstance( classesToBeBound );
-        Marshaller marshaller = context.createMarshaller();
-        marshaller.setProperty( JAXB_ENCODING, encoding.name() );
-        marshaller.setProperty( JAXB_FORMATTED_OUTPUT, true );
-        marshaller.setProperty( JAXB_FRAGMENT, true );
-        marshaller.marshal( rootElement, destination );
-    }
-
-    private static <T> JAXBElement<T> buildJaxbElement( T bean, Class<T> type )
-    {
-        XmlRootElement xmlRootElement = type.getAnnotation( XmlRootElement.class );
-        if ( xmlRootElement == null )
-        {
-            return null;
-        }
-        QName root = new QName( "", xmlRootElement.name() );
-        return new JAXBElement<T>( root, type, bean );
-    }
-
-    private static void properties( Map<String, ?> props, Unmarshaller unmarshaller ) throws PropertyException
-    {
-        for ( Entry<String, ?> e : props.entrySet() )
-        {
-            unmarshaller.setProperty( e.getKey(), e.getValue() );
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/MarshallerUnmarshallerTest.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/MarshallerUnmarshallerTest.java b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/MarshallerUnmarshallerTest.java
index 8d5d32f..96708a8 100644
--- a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/MarshallerUnmarshallerTest.java
+++ b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/MarshallerUnmarshallerTest.java
@@ -19,14 +19,12 @@ package org.apache.maven.plugin.failsafe;
  * under the License.
  */
 
-import org.apache.maven.plugin.failsafe.util.JAXB;
-import org.apache.maven.plugin.failsafe.xmlsummary.FailsafeSummary;
+import org.apache.maven.plugin.failsafe.util.FailsafeSummaryXmlUtils;
+import org.apache.maven.surefire.suite.RunResult;
 import org.junit.Test;
 
 import java.io.File;
 
-import static org.apache.maven.plugin.failsafe.xmlsummary.ErrorType.FAILURE;
-import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
 import static org.fest.assertions.Assertions.assertThat;
 
 public class MarshallerUnmarshallerTest
@@ -35,9 +33,9 @@ public class MarshallerUnmarshallerTest
     public void shouldUnmarshallExistingXmlFile() throws Exception
     {
         File xml = new File( "target/test-classes/org/apache/maven/plugin/failsafe/failsafe-summary.xml" );
-        FailsafeSummary summary = JAXB.unmarshal( xml, FailsafeSummary.class );
+        RunResult summary = FailsafeSummaryXmlUtils.toRunResult( xml );
 
-        assertThat( summary.getCompleted() )
+        assertThat( summary.getCompletedCount() )
                 .isEqualTo( 7 );
 
         assertThat( summary.getErrors() )
@@ -49,14 +47,14 @@ public class MarshallerUnmarshallerTest
         assertThat( summary.getSkipped() )
                 .isEqualTo( 3 );
 
-        assertThat( summary.getFailureMessage() )
+        assertThat( summary.getFailure() )
                 .contains( "There was an error in the forked processtest "
                                    + "subsystem#no method RuntimeException Hi There!"
                 );
 
-        assertThat( summary.getFailureMessage() )
+        assertThat( summary.getFailure() )
                 .contains( "There was an error in the forked processtest "
-                                   + "subsystem#no method RuntimeException Hi There!"
+                                   + "subsystem#no method RuntimeException Hi There! $&>>"
                                    + "\n\tat org.apache.maven.plugin.surefire.booterclient.ForkStarter"
                                    + ".awaitResultsDone(ForkStarter.java:489)"
                 );
@@ -65,23 +63,17 @@ public class MarshallerUnmarshallerTest
     @Test
     public void shouldMarshallAndUnmarshallSameXml() throws Exception
     {
-        FailsafeSummary expected = new FailsafeSummary();
-        expected.setResult( FAILURE );
-        expected.setTimeout( true );
-        expected.setCompleted( 7 );
-        expected.setErrors( 1 );
-        expected.setFailures( 2 );
-        expected.setSkipped( 3 );
-        expected.setFailureMessage( "There was an error in the forked processtest "
-                                            + "subsystem#no method RuntimeException Hi There!"
-                                            + "\n\tat org.apache.maven.plugin.surefire.booterclient.ForkStarter"
-                                            + ".awaitResultsDone(ForkStarter.java:489)"
-        );
+        RunResult expected =
+                new RunResult( 7, 1, 2, 3, 2,
+                                     "There was an error in the forked processtest "
+                                             + "subsystem#no method RuntimeException Hi There! $&>>"
+                                             + "\n\tat org.apache.maven.plugin.surefire.booterclient.ForkStarter"
+                                             + ".awaitResultsDone(ForkStarter.java:489)", true );
 
         File xml = File.createTempFile( "failsafe-summary", ".xml" );
-        JAXB.marshal( expected, UTF_8, xml );
+        FailsafeSummaryXmlUtils.writeSummary( expected, xml, false );
 
-        FailsafeSummary actual = JAXB.unmarshal( xml, FailsafeSummary.class );
+        RunResult actual = FailsafeSummaryXmlUtils.toRunResult( xml );
 
         assertThat( actual.getFailures() )
                 .isEqualTo( expected.getFailures() );
@@ -89,8 +81,8 @@ public class MarshallerUnmarshallerTest
         assertThat( actual.isTimeout() )
                 .isEqualTo( expected.isTimeout() );
 
-        assertThat( actual.getCompleted() )
-                .isEqualTo( expected.getCompleted() );
+        assertThat( actual.getCompletedCount() )
+                .isEqualTo( expected.getCompletedCount() );
 
         assertThat( actual.getErrors() )
                 .isEqualTo( expected.getErrors() );
@@ -101,7 +93,7 @@ public class MarshallerUnmarshallerTest
         assertThat( actual.getSkipped() )
                 .isEqualTo( expected.getSkipped() );
 
-        assertThat( actual.getFailureMessage() )
-                .isEqualTo( expected.getFailureMessage() );
+        assertThat( actual.getFailure() )
+                .isEqualTo( expected.getFailure() );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/RunResultTest.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/RunResultTest.java b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/RunResultTest.java
index f7b62b6..5e75ebf 100644
--- a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/RunResultTest.java
+++ b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/RunResultTest.java
@@ -23,12 +23,9 @@ import org.apache.maven.plugin.failsafe.util.FailsafeSummaryXmlUtils;
 import org.apache.maven.surefire.suite.RunResult;
 import org.junit.Test;
 
-import javax.xml.bind.JAXBException;
 import java.io.File;
-import java.io.IOException;
 import java.nio.charset.Charset;
 
-import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
 import static org.fest.assertions.Assertions.assertThat;
 
 /**
@@ -61,35 +58,35 @@ public class RunResultTest
 
     @Test
     public void testSerialization()
-            throws IOException, JAXBException
+            throws Exception
     {
         writeReadCheck( getSimpleAggregate() );
     }
 
     @Test
     public void testFailures()
-            throws IOException, JAXBException
+            throws Exception
     {
         writeReadCheck( new RunResult( 0, 1, 2, 3, "stacktraceHere", false ) );
     }
 
     @Test
     public void testSkipped()
-            throws IOException, JAXBException
+            throws Exception
     {
         writeReadCheck( new RunResult( 3, 2, 1, 0, null, true ) );
     }
 
     @Test
     public void testAppendSerialization()
-            throws IOException, JAXBException
+            throws Exception
     {
         RunResult simpleAggregate = getSimpleAggregate();
         RunResult additional = new RunResult( 2, 1, 2, 2, "msg " + ( (char) 0x0E01 ), true );
 
         File summary = File.createTempFile( "failsafe", "test" );
-        FailsafeSummaryXmlUtils.writeSummary( simpleAggregate, summary, false, UTF_8 );
-        FailsafeSummaryXmlUtils.writeSummary( additional, summary, true, UTF_8 );
+        FailsafeSummaryXmlUtils.writeSummary( simpleAggregate, summary, false );
+        FailsafeSummaryXmlUtils.writeSummary( additional, summary, true );
         RunResult actual = FailsafeSummaryXmlUtils.toRunResult( summary );
         //noinspection ResultOfMethodCallIgnored
         summary.delete();
@@ -132,7 +129,7 @@ public class RunResultTest
     }
 
     private void writeReadCheck( RunResult expected )
-            throws IOException, JAXBException
+            throws Exception
     {
         File tmp = File.createTempFile( "test", "xml" );
         FailsafeSummaryXmlUtils.fromRunResultToFile( expected, tmp );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/maven-failsafe-plugin/src/test/resources/org/apache/maven/plugin/failsafe/failsafe-summary.xml
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/test/resources/org/apache/maven/plugin/failsafe/failsafe-summary.xml b/maven-failsafe-plugin/src/test/resources/org/apache/maven/plugin/failsafe/failsafe-summary.xml
index b1fe1f9..2b15bca 100644
--- a/maven-failsafe-plugin/src/test/resources/org/apache/maven/plugin/failsafe/failsafe-summary.xml
+++ b/maven-failsafe-plugin/src/test/resources/org/apache/maven/plugin/failsafe/failsafe-summary.xml
@@ -1 +1 @@
-<?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.
-->
<failsafe-summary result="254" timeout="false">
  <completed>7</completed>
  <errors>1</errors>
  <failures>2</failures>
  <skipped>3</skipped>
  <failureMessage>
 <![CDATA[org.apache.maven.surefire.booter.SurefireBooterForkException: ExecutionException There was an error in the forked processtest subsystem#no method RuntimeException Hi There!
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.awaitResultsDone(ForkStarter.java:489)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.runSuitesForkOnceMultiple(ForkStarter.java:364)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:288)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:240)
	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1075)
	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:905)
	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:783)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:133)
	
 at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:108)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:76)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:116)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:361)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:155)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:584)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:213)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:157)
	at 
 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: java.lang.RuntimeException: There was an error in the forked processtest subsystem#no method RuntimeException Hi There!
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:658)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:527)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.acces
 s$500(ForkStarter.java:117)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter$1.call(ForkStarter.java:358)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter$1.call(ForkStarter.java:337)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
]]></failureMessage>
</failsafe-summary>
\ No newline at end of file
+<?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.
-->
<failsafe-summary result="254" timeout="false">
  <completed>7</completed>
  <errors>1</errors>
  <failures>2</failures>
  <skipped>3</skipped>
  <failureMessage>
 <![CDATA[org.apache.maven.surefire.booter.SurefireBooterForkException: ExecutionException There was an error in the forked processtest subsystem#no method RuntimeException Hi There! $&amp;&gt;&gt;
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.awaitResultsDone(ForkStarter.java:489)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.runSuitesForkOnceMultiple(ForkStarter.java:364)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:288)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:240)
	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1075)
	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:905)
	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:783)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginMana
 ger.java:133)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:108)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:76)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:116)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:361)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:155)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:584)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:213)
	at org.apache.maven.cli.MavenCli.main(MavenCli
 .java:157)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: java.lang.RuntimeException: There was an error in the forked processtest subsystem#no method RuntimeException Hi There!
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:658)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:527)
	at org.apache.maven.plugin.surefire.booterclient.Fo
 rkStarter.access$500(ForkStarter.java:117)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter$1.call(ForkStarter.java:358)
	at org.apache.maven.plugin.surefire.booterclient.ForkStarter$1.call(ForkStarter.java:337)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
]]></failureMessage>
</failsafe-summary>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/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/e490b265/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/e490b265/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:tibordigana@apache.org">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/e490b265/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/e490b265/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/e490b265/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/e490b265/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/e490b265/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/e490b265/maven-surefire-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/pom.xml b/maven-surefire-plugin/pom.xml
index 2a186e3..96a1720 100644
--- a/maven-surefire-plugin/pom.xml
+++ b/maven-surefire-plugin/pom.xml
@@ -86,6 +86,7 @@
       </plugin>
       <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.6</version>
         <executions>
           <execution>
             <id>build-site</id>
@@ -103,32 +104,6 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>shade</goal>
-            </goals>
-            <configuration>
-              <minimizeJar>true</minimizeJar>
-              <artifactSet>
-                <includes>
-                  <include>org.apache.maven.shared:maven-shared-utils</include>
-                </includes>
-              </artifactSet>
-              <relocations>
-                <relocation>
-                  <pattern>org.apache.maven.shared</pattern>
-                  <shadedPattern>org.apache.maven.surefire.shade.org.apache.maven.shared</shadedPattern>
-                </relocation>
-              </relocations>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
     </plugins>
   </build>
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6ba5602..0f64b4a 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>
@@ -218,6 +218,11 @@
         <version>${mavenVersion}</version>
       </dependency>
       <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-settings</artifactId>
+        <version>${mavenVersion}</version>
+      </dependency>
+      <dependency>
         <groupId>org.apache.maven.shared</groupId>
         <artifactId>maven-shared-utils</artifactId>
         <version>${mavenSharedUtilsVersion}</version>
@@ -245,6 +250,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 +420,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>
@@ -420,6 +441,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
+        <version>3.0.0-M1</version>
         <executions>
           <execution>
             <id>enforce-java</id>
@@ -429,7 +451,9 @@
             <configuration>
               <rules>
                 <requireJavaVersion>
-                  <version>[1.8.0,)</version>
+                  <!-- We use JDK 1.8 to check -Xdoclint:all at compile time but with javac -source 1.6 -target 1.6 -->
+                  <!-- enforcer:1.3.1 fails on jdk9. 3.0.0-M1 does not but surefire:12.2.4 crashes later. -->
+                  <version>[1.8, 1.9)</version>
                 </requireJavaVersion>
               </rules>
             </configuration>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/e490b265/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/e490b265/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/e490b265/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 ) )