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 2020/05/23 08:46:19 UTC

[maven-surefire] 01/04: [SUREFIRE-1733] Surefire and Failsafe JPMS additions for JUnit 5.x execution

This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch SUREFIRE-1733
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit 265d7cffd03d5acdae4948b3f67f9c83862db587
Author: tibordigana <ti...@apache.org>
AuthorDate: Wed May 6 01:31:12 2020 +0200

    [SUREFIRE-1733] Surefire and Failsafe JPMS additions for JUnit 5.x execution
---
 .../plugin/surefire/AbstractSurefireMojo.java      | 165 +++++++++++++++------
 ...iderInfo.java => ProviderForkRequirements.java} |  40 +++--
 .../apache/maven/plugin/surefire/ProviderInfo.java |   3 +
 .../booterclient/DefaultForkConfiguration.java     |   8 +-
 .../ModularClasspathForkConfiguration.java         |  59 ++++----
 .../AbstractSurefireMojoJava7PlusTest.java         |  14 +-
 .../plugin/surefire/AbstractSurefireMojoTest.java  |  23 ++-
 ...ooterDeserializerProviderConfigurationTest.java |   3 +-
 ...BooterDeserializerStartupConfigurationTest.java |   5 +-
 .../booterclient/DefaultForkConfigurationTest.java |   4 +-
 .../booterclient/ForkConfigurationTest.java        |   8 +-
 .../ModularClasspathForkConfigurationTest.java     |   6 +-
 .../maven/surefire/booter/ModularClasspath.java    |  13 +-
 .../surefire/booter/StartupConfiguration.java      |  13 +-
 .../surefire/its/MultiModuleProjectWithJPMSIT.java |  65 ++++++++
 .../com.foo.api/pom.xml                            |  51 +++++++
 .../src/main/java/com/foo/api/SomeInterface.java   |  22 +--
 .../com.foo.api/src/main/java/module-info.java     |  28 +---
 .../com.foo.impl/pom.xml                           |  85 +++++++++++
 .../src/main/java/com/foo/impl/Bar.java            |  51 +++++++
 .../com.foo.impl/src/main/java/module-info.java    |  26 +---
 .../src/test/java/com/foo/implt/BarIT.java         |  31 ++--
 .../src/test/java/com/foo/implt/BarTest.java       |  31 ++--
 .../com.foo.impl/src/test/java/module-info.java    |  31 ++--
 .../maven-multimodule-project-with-jpms/pom.xml    | 101 +++++++++++++
 25 files changed, 662 insertions(+), 224 deletions(-)

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 8ab5d64..39ca9b7 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
@@ -90,6 +90,7 @@ import org.apache.maven.toolchain.DefaultToolchain;
 import org.apache.maven.toolchain.Toolchain;
 import org.apache.maven.toolchain.ToolchainManager;
 import org.apache.maven.toolchain.java.DefaultJavaToolChain;
+import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
 import org.codehaus.plexus.languages.java.jpms.ResolvePathRequest;
 import org.codehaus.plexus.languages.java.jpms.ResolvePathResult;
 import org.codehaus.plexus.logging.Logger;
@@ -126,6 +127,7 @@ import static java.util.Arrays.asList;
 import static java.util.Collections.addAll;
 import static java.util.Collections.singletonList;
 import static java.util.Collections.singletonMap;
+import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
 import static org.apache.maven.surefire.shared.lang3.StringUtils.substringBeforeLast;
 import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;
 import static org.apache.maven.plugin.surefire.SurefireDependencyResolver.isWithinVersionSpec;
@@ -1388,27 +1390,32 @@ public abstract class AbstractSurefireMojo
 
     private ResolvePathResultWrapper findModuleDescriptor( File jdkHome )
     {
-        File mainBuildPath = getMainBuildPath();
+        ResolvePathResultWrapper test = findModuleDescriptor( jdkHome, getTestClassesDirectory(), false );
+        return test.getResolvePathResult() == null ? findModuleDescriptor( jdkHome, getMainBuildPath(), true ) : test;
+    }
 
-        if ( mainBuildPath.isDirectory() && !new File( mainBuildPath, "module-info.class" ).exists() )
+    private ResolvePathResultWrapper findModuleDescriptor( File jdkHome, File buildPath, boolean isMainDescriptor )
+    {
+        if ( buildPath.isDirectory() && !new File( buildPath, "module-info.class" ).exists() )
         {
-            return new ResolvePathResultWrapper( null, true );
+            return new ResolvePathResultWrapper( null, isMainDescriptor );
         }
 
         try
         {
-            ResolvePathRequest<?> request = ResolvePathRequest.ofFile( mainBuildPath ).setJdkHome( jdkHome );
+            ResolvePathRequest<?> request = ResolvePathRequest.ofFile( buildPath ).setJdkHome( jdkHome );
             ResolvePathResult result = getLocationManager().resolvePath( request );
-            return new ResolvePathResultWrapper( result.getModuleNameSource() == null ? null : result, true );
+            boolean isEmpty = result.getModuleNameSource() == null;
+            return new ResolvePathResultWrapper( isEmpty ? null : result, isMainDescriptor );
         }
         catch ( Exception e )
         {
-            return new ResolvePathResultWrapper( null, true );
+            return new ResolvePathResultWrapper( null, isMainDescriptor );
         }
     }
 
-    private boolean canExecuteProviderWithModularPath( Platform platform,
-                                                       ResolvePathResultWrapper resolvedJavaModularityResult )
+    private boolean canExecuteProviderWithModularPath( @Nonnull Platform platform,
+                                                       @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult )
     {
         return useModulePath()
                 && platform.getJdkExecAttributesForTests().isJava9AtLeast()
@@ -1875,18 +1882,15 @@ public abstract class AbstractSurefireMojo
     {
         try
         {
-            Set<Artifact> providerArtifacts = provider.getProviderClasspath();
-            String providerName = provider.getProviderName();
             if ( isForking && canExecuteProviderWithModularPath( platform, resolvedJavaModularity ) )
             {
                 File jdkHome = platform.getJdkExecAttributesForTests().getJdkHome();
-                return newStartupConfigWithModularPath( classLoaderConfiguration, providerArtifacts, providerName,
-                    resolvedJavaModularity, scanResult, jdkHome.getAbsolutePath(), testClasspathWrapper );
+                return newStartupConfigWithModularPath( classLoaderConfiguration, provider, resolvedJavaModularity,
+                    scanResult, jdkHome.getAbsolutePath(), testClasspathWrapper );
             }
             else
             {
-                return newStartupConfigWithClasspath( classLoaderConfiguration, providerArtifacts, providerName,
-                        testClasspathWrapper );
+                return newStartupConfigWithClasspath( classLoaderConfiguration, provider, testClasspathWrapper );
             }
         }
         catch ( IOException e )
@@ -1896,11 +1900,12 @@ public abstract class AbstractSurefireMojo
     }
 
     private StartupConfiguration newStartupConfigWithClasspath(
-            @Nonnull ClassLoaderConfiguration classLoaderConfiguration, @Nonnull Set<Artifact> providerArtifacts,
-            @Nonnull String providerName, @Nonnull TestClassPath testClasspathWrapper )
+        @Nonnull ClassLoaderConfiguration classLoaderConfiguration, @Nonnull ProviderInfo providerInfo,
+        @Nonnull TestClassPath testClasspathWrapper ) throws MojoExecutionException
     {
         Classpath testClasspath = testClasspathWrapper.toClasspath();
-
+        Set<Artifact> providerArtifacts = providerInfo.getProviderClasspath();
+        String providerName = providerInfo.getProviderName();
         Classpath providerClasspath = classpathCache.getCachedClassPath( providerName );
         if ( providerClasspath == null )
         {
@@ -1921,9 +1926,9 @@ public abstract class AbstractSurefireMojo
 
         ClasspathConfiguration classpathConfiguration = new ClasspathConfiguration( testClasspath, providerClasspath,
                 inProcClasspath, effectiveIsEnableAssertions(), isChildDelegation() );
-
+        ProviderForkRequirements forkRequirements = new ProviderForkRequirements( false, false, false );
         return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration,
-            ProcessCheckerType.toEnum( getEnableProcessChecker() ) );
+            ProcessCheckerType.toEnum( getEnableProcessChecker() ), providerInfo.getJvmArgs( forkRequirements ) );
     }
 
     private static Set<Artifact> retainInProcArtifactsUnique( Set<Artifact> providerArtifacts,
@@ -1975,45 +1980,60 @@ public abstract class AbstractSurefireMojo
     }
 
     private StartupConfiguration newStartupConfigWithModularPath(
-        @Nonnull ClassLoaderConfiguration classLoaderConfiguration, @Nonnull Set<Artifact> providerArtifacts,
-        @Nonnull String providerName, @Nonnull ResolvePathResultWrapper moduleDescriptor,
-        @Nonnull DefaultScanResult scanResult, @Nonnull String javaHome, @Nonnull TestClassPath testClasspathWrapper )
-            throws IOException
+        @Nonnull ClassLoaderConfiguration classLoaderConfiguration, @Nonnull ProviderInfo providerInfo,
+        @Nonnull ResolvePathResultWrapper moduleDescriptor, @Nonnull DefaultScanResult scanResult,
+        @Nonnull String javaHome, @Nonnull TestClassPath testClasspathWrapper )
+            throws MojoExecutionException, IOException
     {
-        Classpath testClasspath = testClasspathWrapper.toClasspath();
+        boolean isMainDescriptor = moduleDescriptor.isMainModuleDescriptor();
+        JavaModuleDescriptor javaModuleDescriptor = moduleDescriptor.getResolvePathResult().getModuleDescriptor();
+        SortedSet<String> packages = new TreeSet<>();
 
+        Classpath testClasspath = testClasspathWrapper.toClasspath();
+        Set<Artifact> providerArtifacts = providerInfo.getProviderClasspath();
+        String providerName = providerInfo.getProviderName();
         Classpath providerClasspath = classpathCache.getCachedClassPath( providerName );
         if ( providerClasspath == null )
         {
             providerClasspath = classpathCache.setCachedClasspath( providerName, providerArtifacts );
         }
 
-        ResolvePathsRequest<String> req = ResolvePathsRequest.ofStrings( testClasspath.getClassPath() )
-                .setJdkHome( javaHome )
-                .setModuleDescriptor( moduleDescriptor.getResolvePathResult().getModuleDescriptor() );
-
-        ResolvePathsResult<String> result = getLocationManager().resolvePaths( req );
-        for ( Entry<String, Exception> entry : result.getPathExceptions().entrySet() )
+        final ProviderForkRequirements forkRequirements;
+        final Classpath testModulepath;
+        if ( isMainDescriptor )
         {
-            // Probably JDK version < 9. Other known causes: passing a non-jar or a corrupted jar.
-            getConsoleLogger()
-                    .warning( "Exception for '" + entry.getKey() + "'.", entry.getValue() );
-        }
+            forkRequirements = new ProviderForkRequirements( true, true, false );
+            ResolvePathsRequest<String> req = ResolvePathsRequest.ofStrings( testClasspath.getClassPath() )
+                    .setJdkHome( javaHome )
+                    .setModuleDescriptor( javaModuleDescriptor );
 
-        testClasspath = new Classpath( result.getClasspathElements() );
-        Classpath testModulepath = new Classpath( result.getModulepathElements().keySet() );
+            ResolvePathsResult<String> result = getLocationManager().resolvePaths( req );
+            for ( Entry<String, Exception> entry : result.getPathExceptions().entrySet() )
+            {
+                // Probably JDK version < 9. Other known causes: passing a non-jar or a corrupted jar.
+                getConsoleLogger()
+                        .warning( "Exception for '" + entry.getKey() + "'.", entry.getValue() );
+            }
 
-        SortedSet<String> packages = new TreeSet<>();
+            testClasspath = new Classpath( result.getClasspathElements() );
+            testModulepath = new Classpath( result.getModulepathElements().keySet() );
 
-        for ( String className : scanResult.getClasses() )
+            for ( String className : scanResult.getClasses() )
+            {
+                packages.add( substringBeforeLast( className, "." ) );
+            }
+        }
+        else
         {
-            packages.add( substringBeforeLast( className, "." ) );
+            forkRequirements = new ProviderForkRequirements( true, false, true );
+            testModulepath = testClasspath;
+            testClasspath = emptyClasspath();
         }
 
-        getConsoleLogger().debug( "main module descriptor name: " + result.getMainModuleDescriptor().name() );
+        getConsoleLogger().debug( "main module descriptor name: " + javaModuleDescriptor.name() );
 
-        ModularClasspath modularClasspath = new ModularClasspath( result.getMainModuleDescriptor().name(),
-                testModulepath.getClassPath(), packages, getTestClassesDirectory() );
+        ModularClasspath modularClasspath = new ModularClasspath( javaModuleDescriptor.name(),
+                testModulepath.getClassPath(), packages, getTestClassesDirectory(), isMainDescriptor );
 
         Artifact[] additionalInProcArtifacts = { getCommonArtifact(), getBooterArtifact(), getExtensionsArtifact(),
             getApiArtifact(), getSpiArtifact(), getLoggerApiArtifact(), getSurefireSharedUtilsArtifact() };
@@ -2033,7 +2053,7 @@ public abstract class AbstractSurefireMojo
         getConsoleLogger().debug( inProcClasspath.getCompactLogMessage( "in-process(compact) classpath:" ) );
 
         return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration,
-            ProcessCheckerType.toEnum( getEnableProcessChecker() ) );
+            ProcessCheckerType.toEnum( getEnableProcessChecker() ), providerInfo.getJvmArgs( forkRequirements ) );
     }
 
     private Artifact getCommonArtifact()
@@ -2344,7 +2364,7 @@ public abstract class AbstractSurefireMojo
                                            @Nonnull RunOrderParameters runOrderParameters, @Nonnull ConsoleLogger log,
                                            @Nonnull DefaultScanResult scanResult,
                                            @Nonnull TestClassPath testClasspathWrapper, @Nonnull Platform platform,
-                                           ResolvePathResultWrapper resolvedJavaModularityResult )
+                                           @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult )
         throws MojoExecutionException, MojoFailureException
     {
         StartupConfiguration startupConfiguration = createStartupConfiguration( provider, true,
@@ -3039,6 +3059,13 @@ public abstract class AbstractSurefireMojo
             convertTestNGParameters();
         }
 
+        @Nonnull
+        @Override
+        public String[] getJvmArgs( @Nonnull ProviderForkRequirements forkRequirements )
+        {
+            return new String[0];
+        }
+
         @Override
         @Nonnull
         public Set<Artifact> getProviderClasspath()
@@ -3069,6 +3096,13 @@ public abstract class AbstractSurefireMojo
         {
         }
 
+        @Nonnull
+        @Override
+        public String[] getJvmArgs( @Nonnull ProviderForkRequirements forkRequirements )
+        {
+            return new String[0];
+        }
+
         @Override
         @Nonnull
         public Set<Artifact> getProviderClasspath()
@@ -3110,6 +3144,13 @@ public abstract class AbstractSurefireMojo
         {
         }
 
+        @Nonnull
+        @Override
+        public String[] getJvmArgs( @Nonnull ProviderForkRequirements forkRequirements )
+        {
+            return new String[0];
+        }
+
         @Override
         @Nonnull
         public Set<Artifact> getProviderClasspath()
@@ -3153,6 +3194,14 @@ public abstract class AbstractSurefireMojo
             convertGroupParameters();
         }
 
+        @Nonnull
+        @Override
+        public String[] getJvmArgs( @Nonnull ProviderForkRequirements forkRequirements )
+        {
+            boolean hasTestDescriptor = forkRequirements.isModularPath() && forkRequirements.hasTestModuleDescriptor();
+            return hasTestDescriptor ? getJpmsArgs() : new String[0];
+        }
+
         @Override
         @Nonnull
         public Set<Artifact> getProviderClasspath() throws MojoExecutionException
@@ -3209,6 +3258,20 @@ public abstract class AbstractSurefireMojo
             return new LinkedHashSet<>( providerArtifacts.values() );
         }
 
+        private String[] getJpmsArgs()
+        {
+            return new String[] {
+                "--add-modules",
+                "ALL-MODULE-PATH",
+
+                "--add-opens",
+                "org.junit.platform.commons/org.junit.platform.commons.util=ALL-UNNAMED",
+
+                "--add-opens",
+                "org.junit.platform.commons/org.junit.platform.commons.logging=ALL-UNNAMED"
+            };
+        }
+
         private void addEngineByApi( String engineGroupId, String engineArtifactId, String engineVersion,
                                      Map<String, Artifact> providerArtifacts )
         {
@@ -3306,6 +3369,13 @@ public abstract class AbstractSurefireMojo
             convertGroupParameters();
         }
 
+        @Nonnull
+        @Override
+        public String[] getJvmArgs( @Nonnull ProviderForkRequirements forkRequirements )
+        {
+            return new String[0];
+        }
+
         @Override
         @Nonnull
         public Set<Artifact> getProviderClasspath()
@@ -3355,6 +3425,13 @@ public abstract class AbstractSurefireMojo
             convertTestNGParameters();
         }
 
+        @Nonnull
+        @Override
+        public String[] getJvmArgs( @Nonnull ProviderForkRequirements forkRequirements )
+        {
+            return new String[0];
+        }
+
         @Override
         @Nonnull
         public Set<Artifact> getProviderClasspath() throws MojoExecutionException
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderForkRequirements.java
similarity index 51%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderForkRequirements.java
index fea74fd..a29da2d 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderForkRequirements.java
@@ -19,24 +19,36 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import javax.annotation.Nonnull;
-import java.util.Set;
-
 /**
- * @author Kristian Rosenvold
+ * Used to get additional provider-specific JVM arguments.
+ *
+ * @see ProviderInfo#getJvmArgs(ProviderForkRequirements)
  */
-public interface ProviderInfo
+final class ProviderForkRequirements
 {
-    @Nonnull
-    String getProviderName();
+    private final boolean modularPath;
+    private final boolean mainModuleDescriptor;
+    private final boolean testModuleDescriptor;
+
+    ProviderForkRequirements( boolean modularPath, boolean mainModuleDescriptor, boolean testModuleDescriptor )
+    {
+        this.modularPath = modularPath;
+        this.mainModuleDescriptor = mainModuleDescriptor;
+        this.testModuleDescriptor = testModuleDescriptor;
+    }
 
-    boolean isApplicable();
+    boolean isModularPath()
+    {
+        return modularPath;
+    }
 
-    @Nonnull
-    Set<Artifact> getProviderClasspath() throws MojoExecutionException;
+    boolean hasMainModuleDescriptor()
+    {
+        return mainModuleDescriptor;
+    }
 
-    void addProviderProperties() throws MojoExecutionException;
+    boolean hasTestModuleDescriptor()
+    {
+        return testModuleDescriptor;
+    }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
index fea74fd..4c76dbc 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
@@ -39,4 +39,7 @@ public interface ProviderInfo
     Set<Artifact> getProviderClasspath() throws MojoExecutionException;
 
     void addProviderProperties() throws MojoExecutionException;
+
+    @Nonnull
+    String[] getJvmArgs( @Nonnull ProviderForkRequirements forkRequirements );
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
index 5336ac6..3f94084 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
@@ -153,6 +153,12 @@ public abstract class DefaultForkConfiguration
                     .setLine( jvmArgLine );
         }
 
+        for ( String arg : config.getProviderForkArgs() )
+        {
+            cli.createArg()
+                .setValue( arg );
+        }
+
         if ( getDebugLine() != null && !getDebugLine().isEmpty() )
         {
             cli.createArg()
@@ -170,7 +176,7 @@ public abstract class DefaultForkConfiguration
     }
 
     @Nonnull
-    protected List<String> toCompleteClasspath( StartupConfiguration conf ) throws SurefireBooterForkException
+    protected List<String> toCompleteClasspath( @Nonnull StartupConfiguration conf ) throws SurefireBooterForkException
     {
         AbstractPathConfiguration pathConfig = conf.getClasspathConfiguration();
         if ( pathConfig.isClassPathConfig() == pathConfig.isModularPathConfig() )
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
index 52729c3..e9ba37c 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
@@ -90,13 +90,15 @@ public class ModularClasspathForkConfiguration
 
             ModularClasspath modularClasspath = modularClasspathConfiguration.getModularClasspath();
 
+            boolean isMainDescriptor = modularClasspath.isMainDescriptor();
             String moduleName = modularClasspath.getModuleNameFromDescriptor();
             List<String> modulePath = modularClasspath.getModulePath();
             Collection<String> packages = modularClasspath.getPackages();
             File patchFile = modularClasspath.getPatchFile();
             List<String> classpath = toCompleteClasspath( config );
 
-            File argsFile = createArgsFile( moduleName, modulePath, classpath, packages, patchFile, startClass );
+            File argsFile =
+                createArgsFile( moduleName, modulePath, classpath, packages, patchFile, startClass, isMainDescriptor );
 
             cli.createArg().setValue( "@" + escapeToPlatformPath( argsFile.getAbsolutePath() ) );
         }
@@ -112,7 +114,7 @@ public class ModularClasspathForkConfiguration
     @Nonnull
     File createArgsFile( @Nonnull String moduleName, @Nonnull List<String> modulePath,
                          @Nonnull List<String> classPath, @Nonnull Collection<String> packages,
-                         @Nonnull File patchFile, @Nonnull String startClassName )
+                         @Nonnull File patchFile, @Nonnull String startClassName, boolean isMainDescriptor )
             throws IOException
     {
         File surefireArgs = createTempFile( "surefireargs", "", getTempDirectory() );
@@ -167,39 +169,42 @@ public class ModularClasspathForkConfiguration
                         .append( NL );
             }
 
-            args.append( "--patch-module" )
-                    .append( NL )
-                    .append( moduleName )
-                    .append( '=' )
-                    .append( '"' )
-                    .append( replace( patchFile.getPath(), "\\", "\\\\" ) )
-                    .append( '"' )
-                    .append( NL );
-
-            for ( String pkg : packages )
+            if ( isMainDescriptor )
             {
-                args.append( "--add-exports" )
+                args.append( "--patch-module" )
+                        .append( NL )
+                        .append( moduleName )
+                        .append( '=' )
+                        .append( '"' )
+                        .append( replace( patchFile.getPath(), "\\", "\\\\" ) )
+                        .append( '"' )
+                        .append( NL );
+
+                for ( String pkg : packages )
+                {
+                    args.append( "--add-exports" )
+                            .append( NL )
+                            .append( moduleName )
+                            .append( '/' )
+                            .append( pkg )
+                            .append( '=' )
+                            .append( "ALL-UNNAMED" )
+                            .append( NL );
+                }
+
+                args.append( "--add-modules" )
+                        .append( NL )
+                        .append( moduleName )
+                        .append( NL );
+
+                args.append( "--add-reads" )
                         .append( NL )
                         .append( moduleName )
-                        .append( '/' )
-                        .append( pkg )
                         .append( '=' )
                         .append( "ALL-UNNAMED" )
                         .append( NL );
             }
 
-            args.append( "--add-modules" )
-                    .append( NL )
-                    .append( moduleName )
-                    .append( NL );
-
-            args.append( "--add-reads" )
-                    .append( NL )
-                    .append( moduleName )
-                    .append( '=' )
-                    .append( "ALL-UNNAMED" )
-                    .append( NL );
-
             args.append( startClassName );
 
             String argsFileContent = args.toString();
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
index d02c7fd..0254440 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
@@ -134,10 +134,10 @@ public class AbstractSurefireMojoJava7PlusTest
         ClassLoaderConfiguration classLoaderConfiguration = new ClassLoaderConfiguration( false, true );
 
         VersionRange v5 = createFromVersion( "1" );
-        Artifact provider = new DefaultArtifact( "org.apache.maven.surefire", "surefire-provider", v5, "runtime",
-                "jar", "", handler );
-        provider.setFile( mockFile( "surefire-provider.jar" ) );
-        Set<Artifact> providerClasspath = singleton( provider );
+        Artifact providerArtifact = new DefaultArtifact( "org.apache.maven.surefire", "surefire-provider",
+            v5, "runtime", "jar", "", handler );
+        providerArtifact.setFile( mockFile( "surefire-provider.jar" ) );
+        Set<Artifact> providerClasspath = singleton( providerArtifact );
 
         ResolvePathResult moduleInfo = mock( ResolvePathResult.class );
         when( moduleInfo.getModuleDescriptor() ).thenReturn( descriptor );
@@ -205,8 +205,12 @@ public class AbstractSurefireMojoJava7PlusTest
         artifacts.put( "org.apache.maven.surefire:surefire-shared-utils", utils );
         when( mojo.getPluginArtifactMap() ).thenReturn( artifacts );
 
+        ProviderInfo providerInfo = mock( ProviderInfo.class );
+        when( providerInfo.getProviderName() ).thenReturn( "org.asf.Provider" );
+        when( providerInfo.getProviderClasspath() ).thenReturn( providerClasspath );
+
         StartupConfiguration conf = invokeMethod( mojo, "newStartupConfigWithModularPath",
-            classLoaderConfiguration, providerClasspath, "org.asf.Provider",
+            classLoaderConfiguration, providerInfo,
             new ResolvePathResultWrapper( moduleInfo, true ), scanResult, "", testClasspath );
 
         verify( mojo, times( 1 ) ).effectiveIsEnableAssertions();
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
index 0440816..1fd97ff 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
@@ -165,6 +165,8 @@ public class AbstractSurefireMojoTest
     {
         AbstractSurefireMojo mojo = spy( new Mojo() );
         mojo.setMainBuildPath( tempFolder.newFolder() );
+        File testClassesDir = tempFolder.newFolder();
+        mojo.setTestClassesDirectory( testClassesDir );
         File jdkHome = new File( System.getProperty( "java.home" ) );
         ResolvePathResultWrapper wrapper = invokeMethod( mojo, "findModuleDescriptor", jdkHome );
 
@@ -200,6 +202,8 @@ public class AbstractSurefireMojoTest
             .when( mojo, "getLocationManager" );
         File classesDir = tempFolder.newFolder();
         mojo.setMainBuildPath( classesDir );
+        File testClassesDir = tempFolder.newFolder();
+        mojo.setTestClassesDirectory( testClassesDir );
         File descriptorFile = new File( classesDir, "module-info.class" );
         assertThat( descriptorFile.createNewFile() ).isTrue();
         File jdkHome = new File( System.getProperty( "java.home" ) );
@@ -255,6 +259,8 @@ public class AbstractSurefireMojoTest
             .when( mojo, "getLocationManager" );
         File classesDir = tempFolder.newFolder();
         mojo.setMainBuildPath( classesDir );
+        File testClassesDir = tempFolder.newFolder();
+        mojo.setTestClassesDirectory( testClassesDir );
 
         File descriptorFile = new File( classesDir, "module-info.class" );
         assertThat( descriptorFile.createNewFile() ).isTrue();
@@ -523,8 +529,12 @@ public class AbstractSurefireMojoTest
         doNothing().when( logger ).debug( anyString() );
         when( mojo.getConsoleLogger() ).thenReturn( new PluginConsoleLogger( logger ) );
 
+        ProviderInfo providerInfo = mock( ProviderInfo.class );
+        when( providerInfo.getProviderName() ).thenReturn( "org.asf.Provider" );
+        when( providerInfo.getProviderClasspath() ).thenReturn( providerArtifacts );
+
         StartupConfiguration conf = invokeMethod( mojo, "newStartupConfigWithClasspath",
-                classLoaderConfiguration, providerArtifacts, "org.asf.Provider", testClasspath );
+                classLoaderConfiguration, providerInfo, testClasspath );
 
         verify( mojo, times( 1 ) ).effectiveIsEnableAssertions();
         verify( mojo, times( 1 ) ).isChildDelegation();
@@ -661,9 +671,6 @@ public class AbstractSurefireMojoTest
         when( resolvePathsResult.getPathExceptions() ).thenReturn( emptyMap() );
         when( resolvePathsResult.getClasspathElements() ).thenReturn( emptyList() );
         when( resolvePathsResult.getModulepathElements() ).thenReturn( emptyMap() );
-        JavaModuleDescriptor desc = mock( JavaModuleDescriptor.class );
-        when( desc.name() ).thenReturn( "" );
-        when( resolvePathsResult.getMainModuleDescriptor() ).thenReturn( desc );
 
         mojo.setLogger( mock( Logger.class ) );
         mojo.setUseModulePath( true );
@@ -703,6 +710,9 @@ public class AbstractSurefireMojoTest
         mojo.setPluginArtifactMap( artifacts );
 
         ResolvePathResult resolvePathResult = mock( ResolvePathResult.class );
+        JavaModuleDescriptor desc = mock( JavaModuleDescriptor.class );
+        when( desc.name() ).thenReturn( "" );
+        when( resolvePathResult.getModuleDescriptor() ).thenReturn( desc );
         ResolvePathResultWrapper wrapper = new ResolvePathResultWrapper( resolvePathResult, true );
         // ### END
 
@@ -2013,6 +2023,7 @@ public class AbstractSurefireMojoTest
             extends AbstractSurefireMojo implements SurefireReportParameters
     {
         private File mainBuildPath;
+        private File testClassesDirectory;
         private boolean useModulePath;
 
         private JUnitPlatformProviderInfo createJUnitPlatformProviderInfo( Artifact junitPlatformArtifact,
@@ -2102,13 +2113,13 @@ public class AbstractSurefireMojoTest
         @Override
         public File getTestClassesDirectory()
         {
-            return null;
+            return testClassesDirectory;
         }
 
         @Override
         public void setTestClassesDirectory( File testClassesDirectory )
         {
-
+            this.testClassesDirectory = testClassesDirectory;
         }
 
         @Override
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 ac3eba5..e4f3acc 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
@@ -286,7 +286,8 @@ public class BooterDeserializerProviderConfigurationTest
     {
         ClasspathConfiguration classpathConfiguration = new ClasspathConfiguration( true, true );
 
-        return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, ALL );
+        return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, ALL,
+            new String[0] );
     }
 
     private File getTestSourceDirectory()
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 5a2d6cf..58d4614 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
@@ -142,7 +142,7 @@ public class BooterDeserializerStartupConfigurationTest
     public void testProcessCheckerNull() throws IOException
     {
         StartupConfiguration startupConfiguration = new StartupConfiguration( "com.provider", classpathConfiguration,
-                getManifestOnlyJarForkConfiguration(), null );
+                getManifestOnlyJarForkConfiguration(), null, new String[0] );
         assertNull( saveAndReload( startupConfiguration ).getProcessChecker() );
     }
 
@@ -204,7 +204,8 @@ public class BooterDeserializerStartupConfigurationTest
 
     private StartupConfiguration getTestStartupConfiguration( ClassLoaderConfiguration classLoaderConfiguration )
     {
-        return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, ALL );
+        return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, ALL,
+            new String[0] );
     }
 
     private File getTestSourceDirectory()
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
index 45a6b4a..8ffd892 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
@@ -307,7 +307,7 @@ public class DefaultForkConfigurationTest
         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
         ClasspathConfiguration cc = new ClasspathConfiguration( true, true );
         StartupConfiguration conf = new StartupConfiguration( "org.apache.maven.shadefire.surefire.MyProvider",
-                cc, clc, null );
+                cc, clc, null, new String[0] );
         StartupConfiguration confMock = spy( conf );
         mockStatic( Relocator.class );
         when( Relocator.relocate( anyString() ) ).thenCallRealMethod();
@@ -328,7 +328,7 @@ public class DefaultForkConfigurationTest
         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
         ClasspathConfiguration cc = new ClasspathConfiguration( true, true );
         StartupConfiguration conf =
-                new StartupConfiguration( "org.apache.maven.surefire.MyProvider", cc, clc, null );
+                new StartupConfiguration( "org.apache.maven.surefire.MyProvider", cc, clc, null, new String[0] );
         StartupConfiguration confMock = spy( conf );
         mockStatic( Relocator.class );
         when( Relocator.relocate( anyString() ) ).thenCallRealMethod();
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 bc01ee8..f2bfe48 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
@@ -57,7 +57,7 @@ public class ForkConfigurationTest
 {
     private static final StartupConfiguration STARTUP_CONFIG = new StartupConfiguration( "",
             new ClasspathConfiguration( true, true ),
-            new ClassLoaderConfiguration( true, true ), ALL );
+            new ClassLoaderConfiguration( true, true ), ALL, new String[0] );
 
     private static int idx = 0;
 
@@ -90,7 +90,7 @@ public class ForkConfigurationTest
         ClasspathConfiguration cpConfig = new ClasspathConfiguration( new Classpath( cp ), emptyClasspath(),
                 emptyClasspath(), true, true );
         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
-        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL );
+        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL, new String[0] );
 
         Commandline cli = config.createCommandLine( startup, 1, temporaryFolder() );
 
@@ -110,7 +110,7 @@ public class ForkConfigurationTest
         ClasspathConfiguration cpConfig = new ClasspathConfiguration( new Classpath( cp ), emptyClasspath(),
                 emptyClasspath(), true, true );
         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
-        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL );
+        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL, new String[0] );
 
         Commandline commandLine = config.createCommandLine( startup, 1, temporaryFolder() );
         assertTrue( commandLine.toString().contains( "abc def" ) );
@@ -125,7 +125,7 @@ public class ForkConfigurationTest
         ClasspathConfiguration cpConfig = new ClasspathConfiguration( emptyClasspath(), emptyClasspath(),
                 emptyClasspath(), true, true );
         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
-        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL );
+        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL, new String[0] );
         ForkConfiguration config = getForkConfiguration( cwd.getCanonicalFile() );
         Commandline commandLine = config.createCommandLine( startup, 1, temporaryFolder() );
 
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java
index cfa7dce..519f700 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java
@@ -80,7 +80,7 @@ public class ModularClasspathForkConfigurationTest
         String startClassName = ForkedBooter.class.getName();
 
         File jigsawArgsFile =
-                config.createArgsFile( "abc", modulePath, classPath, packages, patchFile, startClassName );
+                config.createArgsFile( "abc", modulePath, classPath, packages, patchFile, startClassName, true );
 
         assertThat( jigsawArgsFile )
                 .isNotNull();
@@ -136,7 +136,7 @@ public class ModularClasspathForkConfigurationTest
         assertThat( argsFileLines.get( 12 ) )
                 .isEqualTo( ForkedBooter.class.getName() );
 
-        ModularClasspath modularClasspath = new ModularClasspath( "abc", modulePath, packages, patchFile );
+        ModularClasspath modularClasspath = new ModularClasspath( "abc", modulePath, packages, patchFile, true );
         Classpath testClasspathUrls = new Classpath( singleton( "target" + separator + "test-classes" ) );
         Classpath surefireClasspathUrls = Classpath.emptyClasspath();
         ModularClasspathConfiguration modularClasspathConfiguration =
@@ -144,7 +144,7 @@ public class ModularClasspathForkConfigurationTest
                         emptyClasspath(), true, true );
         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
         StartupConfiguration startupConfiguration = new StartupConfiguration( "JUnitCoreProvider",
-            modularClasspathConfiguration, clc, null );
+            modularClasspathConfiguration, clc, null, new String[0] );
         OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
         config.resolveClasspath( cli, ForkedBooter.class.getName(), startupConfiguration,
                 createTempFile( "surefire", "surefire-reports" ) );
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java
index 7bf8bd0..7dcf0db 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java
@@ -39,15 +39,19 @@ public final class ModularClasspath
     private final List<String> modulePath;
     private final Collection<String> packages;
     private final File patchFile;
+    private final boolean isMainDescriptor;
 
-    public ModularClasspath( @Nonnull String moduleNameFromDescriptor, @Nonnull List<String> modulePath,
+    public ModularClasspath( @Nonnull String moduleNameFromDescriptor,
+                             @Nonnull List<String> modulePath,
                              @Nonnull Collection<String> packages,
-                             @Nonnull File patchFile )
+                             @Nonnull File patchFile,
+                             boolean isMainDescriptor )
     {
         this.moduleNameFromDescriptor = moduleNameFromDescriptor;
         this.modulePath = modulePath;
         this.packages = packages;
         this.patchFile = patchFile;
+        this.isMainDescriptor = isMainDescriptor;
     }
 
     @Nonnull
@@ -73,4 +77,9 @@ public final class ModularClasspath
     {
         return patchFile;
     }
+
+    public boolean isMainDescriptor()
+    {
+        return isMainDescriptor;
+    }
 }
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
index d6a3dd0..846cb0b 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
@@ -34,16 +34,19 @@ public class StartupConfiguration
     private final AbstractPathConfiguration classpathConfiguration;
     private final ClassLoaderConfiguration classLoaderConfiguration;
     private final ProcessCheckerType processChecker;
+    private final String[] providerForkArgs;
 
     public StartupConfiguration( @Nonnull String providerClassName,
                                  @Nonnull AbstractPathConfiguration classpathConfiguration,
                                  @Nonnull ClassLoaderConfiguration classLoaderConfiguration,
-                                 ProcessCheckerType processChecker )
+                                 ProcessCheckerType processChecker,
+                                 @Nonnull String[] providerForkArgs )
     {
         this.classpathConfiguration = classpathConfiguration;
         this.classLoaderConfiguration = classLoaderConfiguration;
         this.providerClassName = providerClassName;
         this.processChecker = processChecker;
+        this.providerForkArgs = providerForkArgs;
     }
 
     public boolean isProviderMainClass()
@@ -56,7 +59,8 @@ public class StartupConfiguration
                                                    ClassLoaderConfiguration classLoaderConfig,
                                                    ProcessCheckerType processChecker )
     {
-        return new StartupConfiguration( providerClassName, classpathConfig, classLoaderConfig, processChecker );
+        return new StartupConfiguration( providerClassName, classpathConfig, classLoaderConfig,
+            processChecker, new String[0] );
     }
 
     public AbstractPathConfiguration getClasspathConfiguration()
@@ -133,4 +137,9 @@ public class StartupConfiguration
     {
         return processChecker;
     }
+
+    public String[] getProviderForkArgs()
+    {
+        return providerForkArgs;
+    }
 }
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/MultiModuleProjectWithJPMSIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/MultiModuleProjectWithJPMSIT.java
new file mode 100644
index 0000000..d7bcae7
--- /dev/null
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/MultiModuleProjectWithJPMSIT.java
@@ -0,0 +1,65 @@
+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.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Integration test for <a href="https://issues.apache.org/jira/browse/SUREFIRE-1733">SUREFIRE-1733</a>.
+ */
+public class MultiModuleProjectWithJPMSIT extends SurefireJUnit4IntegrationTestCase
+{
+    @Test
+    public void test() throws Exception
+    {
+        OutputValidator validator = unpack( "maven-multimodule-project-with-jpms" )
+            .debugLogging()
+            .executeVerify()
+            .verifyErrorFreeLog()
+            .assertThatLogLine( containsString( "Lets see JDKModulePath" ), is( 2 ) )
+            .assertThatLogLine( containsString( "Lets see JDKModulePath: null" ), is( 0 ) );
+
+        List<String> lines = validator.loadLogLines( containsString( "Lets see JDKModulePath" ) );
+        int i = 0;
+        for ( String line : lines )
+        {
+            assertThat( line )
+                .contains( "com.foo.api" )
+                .contains( "junit-jupiter-api" )
+                .contains( "junit-jupiter-engine" )
+                .contains( "slf4j-simple" )
+                .contains( "slf4j-api" )
+                .contains( "jakarta.xml.bind-api" )
+                .contains( "jakarta.ws.rs-api" )
+                .contains( "jakarta.persistence-api" );
+
+            assertThat( line )
+                .contains( i++ == 0 ? "test-classes" : "com.foo.impl" );
+        }
+    }
+}
diff --git a/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/pom.xml b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/pom.xml
new file mode 100644
index 0000000..6e1883c
--- /dev/null
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/pom.xml
@@ -0,0 +1,51 @@
+<?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>com.foo</groupId>
+        <artifactId>com.foo</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>com.foo.api</artifactId>
+    
+    <dependencies>
+        <dependency>
+            <groupId>jakarta.persistence</groupId>
+            <artifactId>jakarta.persistence-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.ws.rs</groupId>
+            <artifactId>jakarta.ws.rs-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.xml.bind</groupId>
+            <artifactId>jakarta.xml.bind-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/src/main/java/com/foo/api/SomeInterface.java
similarity index 63%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
copy to surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/src/main/java/com/foo/api/SomeInterface.java
index fea74fd..43ecf73 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/src/main/java/com/foo/api/SomeInterface.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire;
+package com.foo.api;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,24 +19,10 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import javax.annotation.Nonnull;
-import java.util.Set;
-
 /**
- * @author Kristian Rosenvold
+ *
  */
-public interface ProviderInfo
+public interface SomeInterface
 {
-    @Nonnull
-    String getProviderName();
-
-    boolean isApplicable();
-
-    @Nonnull
-    Set<Artifact> getProviderClasspath() throws MojoExecutionException;
-
-    void addProviderProperties() throws MojoExecutionException;
+    void doItNow( Class<?> observer );
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/src/main/java/module-info.java
similarity index 62%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
copy to surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/src/main/java/module-info.java
index fea74fd..95b05f7 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.api/src/main/java/module-info.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.surefire;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,24 +17,12 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import javax.annotation.Nonnull;
-import java.util.Set;
-
-/**
- * @author Kristian Rosenvold
- */
-public interface ProviderInfo
+module com.foo.api
 {
-    @Nonnull
-    String getProviderName();
-
-    boolean isApplicable();
-
-    @Nonnull
-    Set<Artifact> getProviderClasspath() throws MojoExecutionException;
-
-    void addProviderProperties() throws MojoExecutionException;
+    exports com.foo.api;
+    requires org.slf4j;
+    requires java.persistence;
+    requires java.ws.rs;
+    requires java.xml.bind;
+    requires jakarta.activation;
 }
diff --git a/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/pom.xml b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/pom.xml
new file mode 100644
index 0000000..fd160fe
--- /dev/null
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/pom.xml
@@ -0,0 +1,85 @@
+<?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>com.foo</groupId>
+        <artifactId>com.foo</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>com.foo.impl</artifactId>
+    
+    <dependencies>
+        <dependency>
+            <groupId>com.foo</groupId>
+            <artifactId>com.foo.api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+<!--                    <multiReleaseOutput>true</multiReleaseOutput>-->
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestEntries>
+<!--                            <Multi-Release>true</Multi-Release>-->
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>integration-tests</id>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/main/java/com/foo/impl/Bar.java b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/main/java/com/foo/impl/Bar.java
new file mode 100644
index 0000000..50009e3
--- /dev/null
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/main/java/com/foo/impl/Bar.java
@@ -0,0 +1,51 @@
+package com.foo.impl;
+
+/*
+ * 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 com.foo.api.SomeInterface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class Bar implements SomeInterface
+{
+    private static final Logger LOG = LoggerFactory.getLogger( Bar.class );
+
+    private boolean weAreAmongModules;
+
+    @Override
+    public void doItNow( Class<?> observer )
+    {
+        ModuleLayer.boot().modules().forEach( m -> {
+            if ( m == observer.getModule() || m == Bar.class.getModule() || m == Logger.class.getModule() )
+            {
+                weAreAmongModules = true;
+            }
+        } );
+        LOG.info( "" );
+        LOG.info( "Let's see if I or SLF4J are among boot layer modules: {}", weAreAmongModules );
+        if ( !weAreAmongModules )
+        {
+            LOG.info( "Maybe we are in child layer? Or this is not module path?" );
+        }
+    }
+}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/main/java/module-info.java
similarity index 62%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
copy to surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/main/java/module-info.java
index fea74fd..13ca174 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/main/java/module-info.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.surefire;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,24 +17,10 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import javax.annotation.Nonnull;
-import java.util.Set;
-
-/**
- * @author Kristian Rosenvold
- */
-public interface ProviderInfo
+module com.foo.impl
 {
-    @Nonnull
-    String getProviderName();
-
-    boolean isApplicable();
-
-    @Nonnull
-    Set<Artifact> getProviderClasspath() throws MojoExecutionException;
-
-    void addProviderProperties() throws MojoExecutionException;
+    exports com.foo.impl;
+    requires com.foo.api;
+    requires org.slf4j;
+    requires org.slf4j.simple;
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/com/foo/implt/BarIT.java
similarity index 62%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
copy to surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/com/foo/implt/BarIT.java
index fea74fd..acb4c7f 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/com/foo/implt/BarIT.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire;
+package com.foo.implt;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,24 +19,25 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.MojoExecutionException;
+import com.foo.impl.Bar;
 
-import javax.annotation.Nonnull;
-import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * @author Kristian Rosenvold
+ *
  */
-public interface ProviderInfo
+public class BarIT
 {
-    @Nonnull
-    String getProviderName();
-
-    boolean isApplicable();
-
-    @Nonnull
-    Set<Artifact> getProviderClasspath() throws MojoExecutionException;
+    private static final Logger LOG = LoggerFactory.getLogger( BarIT.class );
 
-    void addProviderProperties() throws MojoExecutionException;
+    @Test
+    void shouldPrintModulePath()
+    {
+        Bar bar = new Bar();
+        LOG.info( "======INTEGRATION TEST=======" );
+        LOG.info( "Lets see JDKModulePath: {}", System.getProperty( "jdk.module.path" ) );
+        bar.doItNow( getClass() );
+    }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/com/foo/implt/BarTest.java
similarity index 62%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
copy to surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/com/foo/implt/BarTest.java
index fea74fd..f639198 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/com/foo/implt/BarTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire;
+package com.foo.implt;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,24 +19,25 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.MojoExecutionException;
+import com.foo.impl.Bar;
 
-import javax.annotation.Nonnull;
-import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * @author Kristian Rosenvold
+ *
  */
-public interface ProviderInfo
+public class BarTest
 {
-    @Nonnull
-    String getProviderName();
-
-    boolean isApplicable();
-
-    @Nonnull
-    Set<Artifact> getProviderClasspath() throws MojoExecutionException;
+    private static final Logger LOG = LoggerFactory.getLogger( BarTest.class );
 
-    void addProviderProperties() throws MojoExecutionException;
+    @Test
+    void shouldPrintModulePath()
+    {
+        Bar bar = new Bar();
+        LOG.info( "======UNIT TEST=======" );
+        LOG.info( "Lets see JDKModulePath: {}", System.getProperty( "jdk.module.path" ) );
+        bar.doItNow( getClass() );
+    }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/module-info.java
similarity index 62%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
copy to surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/module-info.java
index fea74fd..60ba2dc 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/ProviderInfo.java
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/com.foo.impl/src/test/java/module-info.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.surefire;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,24 +17,15 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import javax.annotation.Nonnull;
-import java.util.Set;
-
-/**
- * @author Kristian Rosenvold
- */
-public interface ProviderInfo
+open module com.foo.test
 {
-    @Nonnull
-    String getProviderName();
-
-    boolean isApplicable();
-
-    @Nonnull
-    Set<Artifact> getProviderClasspath() throws MojoExecutionException;
-
-    void addProviderProperties() throws MojoExecutionException;
+    requires com.foo.impl;
+    requires org.slf4j;
+    requires org.slf4j.simple;
+    //requires org.junit.platform.launcher;
+    requires org.junit.jupiter.engine;
+    requires org.junit.jupiter.api;
+    requires org.apiguardian.api;
+    //requires org.junit.platform.commons;
+    requires org.opentest4j;
 }
diff --git a/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/pom.xml b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/pom.xml
new file mode 100644
index 0000000..00e047f
--- /dev/null
+++ b/surefire-its/src/test/resources/maven-multimodule-project-with-jpms/pom.xml
@@ -0,0 +1,101 @@
+<?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>
+
+    <groupId>com.foo</groupId>
+    <artifactId>com.foo</artifactId>
+    <version>1.0.0</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.release>${java.specification.version}</maven.compiler.release>
+    </properties>
+
+    <modules>
+        <module>com.foo.api</module>
+        <module>com.foo.impl</module>
+    </modules>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>jakarta.persistence</groupId>
+                <artifactId>jakarta.persistence-api</artifactId>
+                <version>2.2.3</version>
+            </dependency>
+            <dependency>
+                <groupId>jakarta.ws.rs</groupId>
+                <artifactId>jakarta.ws.rs-api</artifactId>
+                <version>2.1.6</version>
+            </dependency>
+            <dependency>
+                <groupId>jakarta.xml.bind</groupId>
+                <artifactId>jakarta.xml.bind-api</artifactId>
+                <version>2.3.2</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>1.8.0-beta2</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-simple</artifactId>
+                <version>1.8.0-beta2</version>
+            </dependency>
+            <dependency>
+               <groupId>org.junit.jupiter</groupId>
+               <artifactId>junit-jupiter-engine</artifactId>
+               <version>5.6.2</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.8.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>${surefire.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>3.2.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-failsafe-plugin</artifactId>
+                    <version>${surefire.version}</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+</project>