[MNG-5668] Dynamic component resolution to allow older Maven versions to fail gracefully

Example on a project that has the experimental features enabled:

    $ mvn -version
    Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-17T19:33:14+01:00)
    Maven home: /usr/local/Cellar/maven/3.5.4/libexec
    Java version: 1.8.0_152, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre
    Default locale: en_IE, platform encoding: UTF-8
    OS name: "mac os x", version: "10.14.6", arch: "x86_64", family: "mac"
    $ mvn validate
    [ERROR] The project uses experimental features that require exactly Maven 3.7.0-SNAPSHOT -> [Help 1]
    [ERROR]
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR]
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MavenExecutionException
diff --git a/maven-experiments/src/main/java/org/apache/maven/feature/check/Helper.java b/maven-experiments/src/main/java/org/apache/maven/feature/check/Helper.java
new file mode 100644
index 0000000..eda0433
--- /dev/null
+++ b/maven-experiments/src/main/java/org/apache/maven/feature/check/Helper.java
@@ -0,0 +1,50 @@
+package org.apache.maven.feature.check;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+
+import org.apache.maven.MavenExecutionException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.feature.api.MavenFeatures;
+import org.apache.maven.feature.spi.DefaultMavenFeatures;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+/**
+ * Helper class to work around class scanning/loading issues.
+ */
+class Helper
+{
+    static void enableFeatures( MavenSession session, String targetVersion, PlexusContainer container,
+                                File topLevelProjectFile )
+        throws MavenExecutionException, ClassNotFoundException, ComponentLookupException
+    {
+        MavenFeatures features = container.lookup( MavenFeatures.class, "default" );
+        if ( !( features instanceof DefaultMavenFeatures ) )
+        {
+            throw new MavenExecutionException(
+                "This project uses experimental features that require exactly Maven " + targetVersion
+                    + ", cannot enable experimental features because feature flag component is not as expected (was: "
+                    + features + ")", topLevelProjectFile );
+        }
+        ( (DefaultMavenFeatures) features ).enable( session );
+    }
+}
diff --git a/maven-experiments/src/main/java/org/apache/maven/feature/check/MavenExperimentEnabler.java b/maven-experiments/src/main/java/org/apache/maven/feature/check/MavenExperimentEnabler.java
index 26e2ee4..4ef526c 100644
--- a/maven-experiments/src/main/java/org/apache/maven/feature/check/MavenExperimentEnabler.java
+++ b/maven-experiments/src/main/java/org/apache/maven/feature/check/MavenExperimentEnabler.java
@@ -32,10 +32,10 @@
 import org.apache.maven.Maven;
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.feature.api.MavenFeatures;
-import org.apache.maven.feature.spi.DefaultMavenFeatures;
+import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.annotations.Component;
 import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.logging.Logger;
 
 /**
@@ -49,8 +49,8 @@
     @Requirement
     private Logger log;
 
-    @Requirement( role = MavenFeatures.class, hint = "default", optional = true )
-    private MavenFeatures features;
+    @Requirement
+    private PlexusContainer container;
 
     private final Map<MavenSession, Void> startedSessions = new WeakHashMap<>();
 
@@ -112,9 +112,9 @@
         }
         try
         {
-            enableFeatures( session, targetVersion );
+            Helper.enableFeatures( session, targetVersion, this.container, this.topLevelProjectFile( session ) );
         }
-        catch ( LinkageError e )
+        catch ( LinkageError | ClassNotFoundException | ComponentLookupException e )
         {
             throw new MavenExecutionException(
                 "The project uses experimental features that require exactly Maven " + targetVersion,
@@ -122,19 +122,6 @@
         }
     }
 
-    private void enableFeatures( MavenSession session, String targetVersion )
-        throws MavenExecutionException
-    {
-        if ( !( features instanceof DefaultMavenFeatures ) )
-        {
-            throw new MavenExecutionException(
-                "This project uses experimental features that require exactly Maven " + targetVersion
-                    + ", cannot enable experimental features because feature flag component is not as expected (was: "
-                    + features + ")", topLevelProjectFile( session ) );
-        }
-        ( (DefaultMavenFeatures) features ).enable( session );
-    }
-
     private File topLevelProjectFile( MavenSession session )
     {
         return session.getTopLevelProject() != null ? session.getTopLevelProject().getFile() : null;