You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sj...@apache.org on 2022/12/28 15:02:00 UTC

[maven-enforcer] 01/01: [MENFORCER-453] Mange rules configuration by plugin

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

sjaranowski pushed a commit to branch MENFORCER-453
in repository https://gitbox.apache.org/repos/asf/maven-enforcer.git

commit 710e29edf9ca602e965e4ec4df1362f7339cf0b0
Author: Slawomir Jaranowski <s....@gmail.com>
AuthorDate: Wed Dec 28 15:55:52 2022 +0100

    [MENFORCER-453] Mange rules configuration by plugin
---
 enforcer-rules/pom.xml                             |  11 +-
 .../maven/plugins/enforcer/EnforcerRuleDesc.java   |  31 +++-
 .../plugins/enforcer/EnforcerRuleManager.java      | 115 +++++++++++++
 .../enforcer/EnforcerRuleManagerException.java     |  18 +-
 .../plugins/enforcer/EnforcerRuleManagerTest.java  | 183 +++++++++++++++++++++
 .../apache/maven/plugins/enforcer/EnforceMojo.java | 106 ++++++------
 .../maven/plugins/enforcer/TestEnforceMojo.java    | 150 +++++++++--------
 7 files changed, 486 insertions(+), 128 deletions(-)

diff --git a/enforcer-rules/pom.xml b/enforcer-rules/pom.xml
index 2a9b2a0..efa660b 100644
--- a/enforcer-rules/pom.xml
+++ b/enforcer-rules/pom.xml
@@ -100,7 +100,7 @@
     </dependency>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
+      <artifactId>junit-jupiter-api</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -108,6 +108,11 @@
       <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-junit-jupiter</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.assertj</groupId>
       <artifactId>assertj-core</artifactId>
@@ -118,6 +123,10 @@
 
   <build>
     <plugins>
+      <plugin>
+        <groupId>org.eclipse.sisu</groupId>
+        <artifactId>sisu-maven-plugin</artifactId>
+      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
diff --git a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/util/EnforcerUtils.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleDesc.java
similarity index 57%
copy from maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/util/EnforcerUtils.java
copy to enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleDesc.java
index b053904..84d5977 100644
--- a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/util/EnforcerUtils.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleDesc.java
@@ -16,10 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.util;
+package org.apache.maven.plugins.enforcer;
+
+import org.apache.maven.enforcer.rule.api.EnforcerRule;
 
 /**
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- *
+ * Description of rule to eecute.
  */
-public class EnforcerUtils {}
+public class EnforcerRuleDesc {
+
+    private final String name;
+    private final EnforcerRule rule;
+
+    /**
+     * Create a new Rule Description
+     * @param name a rule name
+     * @param rule a rule instance
+     */
+    EnforcerRuleDesc(String name, EnforcerRule rule) {
+        this.name = name;
+        this.rule = rule;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public EnforcerRule getRule() {
+        return rule;
+    }
+}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManager.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManager.java
new file mode 100644
index 0000000..07531c9
--- /dev/null
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManager.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugins.enforcer;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.ComponentConfigurator;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+
+/**
+ * Manage enforcer rules.
+ */
+@Named
+@Singleton
+public class EnforcerRuleManager {
+
+    @Inject
+    private Provider<MavenSession> sessionProvider;
+
+    @Inject
+    private Provider<MojoExecution> mojoExecutionProvider;
+
+    @Inject
+    @Named("basic")
+    private ComponentConfigurator componentConfigurator;
+
+    /**
+     * Create enforcer rules based on xml configuration.
+     *
+     * @param rules a rules configuration
+     * @return List of rule instances
+     * @throws EnforcerRuleManagerException report a problem during rules creating
+     */
+    public List<EnforcerRuleDesc> createRules(PlexusConfiguration rules) throws EnforcerRuleManagerException {
+
+        List<EnforcerRuleDesc> result = new ArrayList<>();
+
+        if (rules == null || rules.getChildCount() == 0) {
+            return result;
+        }
+
+        ClassRealm classRealm = mojoExecutionProvider
+                .get()
+                .getMojoDescriptor()
+                .getPluginDescriptor()
+                .getClassRealm();
+
+        ExpressionEvaluator evaluator =
+                new PluginParameterExpressionEvaluator(sessionProvider.get(), mojoExecutionProvider.get());
+
+        for (PlexusConfiguration ruleConfig : rules.getChildren()) {
+            EnforcerRuleDesc ruleDesc = createRuleDesc(ruleConfig.getName(), ruleConfig.getAttribute("implementation"));
+            if (ruleConfig.getChildCount() > 0) {
+                try {
+                    componentConfigurator.configureComponent(ruleDesc.getRule(), ruleConfig, evaluator, classRealm);
+                } catch (ComponentConfigurationException e) {
+                    throw new EnforcerRuleManagerException(e);
+                }
+            }
+            result.add(ruleDesc);
+        }
+        return result;
+    }
+
+    private EnforcerRuleDesc createRuleDesc(String name, String implementation) throws EnforcerRuleManagerException {
+
+        String ruleClass;
+        if (implementation != null && !implementation.isEmpty()) {
+            ruleClass = implementation;
+        } else {
+            ruleClass = name;
+        }
+
+        if (!ruleClass.contains(".")) {
+            ruleClass = getClass().getPackage().getName() + "." + Character.toUpperCase(ruleClass.charAt(0))
+                    + ruleClass.substring(1);
+        }
+
+        try {
+            return new EnforcerRuleDesc(
+                    name, (EnforcerRule) Class.forName(ruleClass).newInstance());
+        } catch (Exception e) {
+            throw new EnforcerRuleManagerException("Failed to create enforcer rules for class: " + ruleClass, e);
+        }
+    }
+}
diff --git a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/util/EnforcerUtils.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerException.java
similarity index 65%
rename from maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/util/EnforcerUtils.java
rename to enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerException.java
index b053904..29e20af 100644
--- a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/util/EnforcerUtils.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerException.java
@@ -16,10 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.util;
+package org.apache.maven.plugins.enforcer;
 
 /**
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- *
+ * Problems reported by EnforcerRuleManager.
  */
-public class EnforcerUtils {}
+public class EnforcerRuleManagerException extends Exception {
+
+    private static final long serialVersionUID = -7559335919839629986L;
+
+    public EnforcerRuleManagerException(Throwable cause) {
+        super(cause);
+    }
+
+    public EnforcerRuleManagerException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerTest.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerTest.java
new file mode 100644
index 0000000..99626cd
--- /dev/null
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerTest.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugins.enforcer;
+
+import javax.inject.Provider;
+
+import java.util.List;
+
+import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.ComponentConfigurator;
+import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class EnforcerRuleManagerTest {
+
+    @Mock
+    private Provider<MavenSession> sessionProvider;
+
+    @Mock
+    private Provider<MojoExecution> mojoExecutionProvider;
+
+    @Mock
+    private ComponentConfigurator componentConfigurator;
+
+    @InjectMocks
+    private EnforcerRuleManager enforcerRuleManager;
+
+    void setupMocks() {
+        MojoExecution mojoExecution = mock(MojoExecution.class);
+        when(mojoExecutionProvider.get()).thenReturn(mojoExecution);
+
+        MojoDescriptor mojoDescriptor = mock(MojoDescriptor.class);
+        when(mojoExecution.getMojoDescriptor()).thenReturn(mojoDescriptor);
+
+        when(mojoDescriptor.getPluginDescriptor()).thenReturn(mock(PluginDescriptor.class));
+
+        when(sessionProvider.get()).thenReturn(mock(MavenSession.class));
+    }
+
+    @Test
+    void nulConfigReturnEmptyRules() throws Exception {
+
+        List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(null);
+
+        assertThat(rules).isEmpty();
+    }
+
+    @Test
+    void emptyConfigReturnEmptyRules() throws Exception {
+
+        List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(new DefaultPlexusConfiguration("rules"));
+
+        assertThat(rules).isEmpty();
+    }
+
+    @Test
+    void unKnownRuleThrowException() {
+
+        setupMocks();
+
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules").addChild("UnKnowRule", null);
+
+        assertThatCode(() -> enforcerRuleManager.createRules(configuration))
+                .isInstanceOf(EnforcerRuleManagerException.class)
+                .hasMessage("Failed to create enforcer rules for class: org.apache.maven.plugins.enforcer.UnKnowRule")
+                .hasCauseInstanceOf(ClassNotFoundException.class);
+    }
+
+    @Test
+    void invalidConfigurationThrowException() throws ComponentConfigurationException {
+
+        setupMocks();
+
+        PlexusConfiguration ruleConfig =
+                new DefaultPlexusConfiguration("alwaysPass").addChild("message", "messageValue");
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules");
+        configuration.addChild(ruleConfig);
+
+        doThrow(ComponentConfigurationException.class)
+                .when(componentConfigurator)
+                .configureComponent(any(), any(), any(), any());
+
+        assertThatCode(() -> enforcerRuleManager.createRules(configuration))
+                .isInstanceOf(EnforcerRuleManagerException.class)
+                .hasCauseInstanceOf(ComponentConfigurationException.class);
+    }
+
+    @Test
+    void createSimpleRule() throws EnforcerRuleManagerException {
+
+        setupMocks();
+
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules")
+                .addChild("AlwaysFail", null)
+                .addChild("alwaysPass", null);
+
+        List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(configuration);
+
+        assertThat(rules)
+                .hasSize(2)
+                .map(EnforcerRuleDesc::getRule)
+                .hasExactlyElementsOfTypes(AlwaysFail.class, AlwaysPass.class);
+
+        assertThat(rules).hasSize(2).map(EnforcerRuleDesc::getName).containsExactly("AlwaysFail", "alwaysPass");
+    }
+
+    @Test
+    void createRuleWithImplementation() throws EnforcerRuleManagerException {
+
+        setupMocks();
+
+        PlexusConfiguration ruleConfig = new DefaultPlexusConfiguration("alwaysPassWithImp");
+        ruleConfig.setAttribute("implementation", AlwaysPass.class.getName());
+
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules");
+        configuration.addChild(ruleConfig);
+
+        List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(configuration);
+
+        assertThat(rules).hasSize(1).map(EnforcerRuleDesc::getRule).hasExactlyElementsOfTypes(AlwaysPass.class);
+
+        assertThat(rules).hasSize(1).map(EnforcerRuleDesc::getName).containsExactly("alwaysPassWithImp");
+    }
+
+    @Test
+    void ruleShouldBeConfigured() throws EnforcerRuleManagerException, ComponentConfigurationException {
+
+        setupMocks();
+
+        PlexusConfiguration ruleConfig =
+                new DefaultPlexusConfiguration("alwaysPass").addChild("message", "messageValue");
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules");
+        configuration.addChild(ruleConfig);
+
+        List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(configuration);
+        assertThat(rules).hasSize(1);
+
+        ArgumentCaptor<EnforcerRule> ruleCaptor = ArgumentCaptor.forClass(EnforcerRule.class);
+        ArgumentCaptor<PlexusConfiguration> configurationCaptor = ArgumentCaptor.forClass(PlexusConfiguration.class);
+
+        verify(componentConfigurator)
+                .configureComponent(ruleCaptor.capture(), configurationCaptor.capture(), any(), any());
+
+        assertThat(ruleCaptor.getValue()).isInstanceOf(AlwaysPass.class);
+        assertThat(configurationCaptor.getValue()).isSameAs(ruleConfig);
+    }
+}
diff --git a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java
index 361e970..f27be95 100644
--- a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java
@@ -20,7 +20,9 @@ package org.apache.maven.plugins.enforcer;
 
 import java.util.Hashtable;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.maven.enforcer.rule.api.EnforcerLevel;
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
@@ -40,19 +42,19 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
 
 /**
  * This goal executes the defined enforcer-rules once per module.
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
-// CHECKSTYLE_OFF: LineLength
 @Mojo(
         name = "enforce",
         defaultPhase = LifecyclePhase.VALIDATE,
         requiresDependencyCollection = ResolutionScope.TEST,
         threadSafe = true)
-// CHECKSTYLE_ON: LineLength
 public class EnforceMojo extends AbstractMojo {
     /**
      * This is a static variable used to persist the cached results across plugin invocations.
@@ -104,10 +106,24 @@ public class EnforceMojo extends AbstractMojo {
     private boolean failIfNoRules = true;
 
     /**
-     * Array of objects that implement the EnforcerRule interface to execute.
+     * Rules configuration to execute as XML.
+     * Each first level tag represents rule name to execute.
+     * Inner tags are configurations for rule.
+     * Eg:
+     * <pre>
+     *     &lt;rules&gt;
+     *         &lt;alwaysFail/&gt;
+     *         &lt;alwaysPass&gt;
+     *             &lt;message&gt;message for rule&lt;/message&gt;
+     *         &lt;/alwaysPass&gt;
+     *         &lt;myRule implementation="org.example.MyRule"/&gt;
+     *     &lt;/rules>
+     * </pre>
+     *
+     * @since 1.0.0
      */
-    @Parameter(required = false)
-    private EnforcerRule[] rules;
+    @Parameter
+    private PlexusConfiguration rules;
 
     /**
      * Array of Strings that matches the EnforcerRules to execute.
@@ -123,32 +139,34 @@ public class EnforceMojo extends AbstractMojo {
     protected boolean ignoreCache = false;
 
     @Component
-    protected PlexusContainer container;
+    private PlexusContainer container;
 
-    private boolean havingRules() {
-        return rules != null && rules.length > 0;
-    }
+    @Component
+    private EnforcerRuleManager enforcerRuleManager;
 
     @Override
     public void execute() throws MojoExecutionException {
         Log log = this.getLog();
 
-        PluginParameterExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
-        if (commandLineRules != null && commandLineRules.length > 0) {
-            this.rules = createRulesFromCommandLineOptions();
-        }
-
         if (isSkip()) {
             log.info("Skipping Rule Enforcement.");
             return;
         }
 
-        if (!havingRules()) {
+        Optional<PlexusConfiguration> rulesFromCommandLine = createRulesFromCommandLineOptions();
+
+        List<EnforcerRuleDesc> rulesList;
+        try {
+            // current behavior - rules from command line override all other configured rules.
+            rulesList = enforcerRuleManager.createRules(rulesFromCommandLine.orElse(rules));
+        } catch (EnforcerRuleManagerException e) {
+            throw new MojoExecutionException(e.getMessage(), e);
+        }
+
+        if (rulesList.isEmpty()) {
             if (isFailIfNoRules()) {
-                // CHECKSTYLE_OFF: LineLength
                 throw new MojoExecutionException(
                         "No rules are configured. Use the skip flag if you want to disable execution.");
-                // CHECKSTYLE_ON: LineLength
             } else {
                 log.warn("No rules are configured.");
                 return;
@@ -161,6 +179,7 @@ public class EnforceMojo extends AbstractMojo {
         String currentRule = "Unknown";
 
         // create my helper
+        PluginParameterExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
         EnforcerRuleHelper helper = new DefaultEnforcementRuleHelper(session, evaluator, log, container);
 
         // if we are only warning, then disable
@@ -172,12 +191,13 @@ public class EnforceMojo extends AbstractMojo {
         boolean hasErrors = false;
 
         // go through each rule
-        for (int i = 0; i < rules.length; i++) {
+        for (int i = 0; i < rulesList.size(); i++) {
 
             // prevent against empty rules
-            EnforcerRule rule = rules[i];
-            final EnforcerLevel level = getLevel(rule);
-            if (rule != null) {
+            EnforcerRuleDesc ruleDesc = rulesList.get(i);
+            if (ruleDesc != null) {
+                EnforcerRule rule = ruleDesc.getRule();
+                EnforcerLevel level = getLevel(rule);
                 // store the current rule for
                 // logging purposes
                 currentRule = rule.getClass().getName();
@@ -242,22 +262,24 @@ public class EnforceMojo extends AbstractMojo {
         // CHECKSTYLE_ON: LineLength
     }
 
-    private EnforcerRule[] createRulesFromCommandLineOptions() throws MojoExecutionException {
-        EnforcerRule[] rules = new EnforcerRule[commandLineRules.length];
-        for (int i = 0; i < commandLineRules.length; i++) {
-            String rule = commandLineRules[i];
-            if (!rule.contains(".")) {
-                rule = getClass().getPackage().getName() + "." + Character.toUpperCase(rule.charAt(0))
-                        + rule.substring(1);
-            }
+    /**
+     * Create rules configuration based on command line provided rules list.
+     *
+     * @return an configuration in case where rules list is present or empty
+     */
+    private Optional<PlexusConfiguration> createRulesFromCommandLineOptions() {
 
-            try {
-                rules[i] = (EnforcerRule) Class.forName(rule).newInstance();
-            } catch (Exception e) {
-                throw new MojoExecutionException("Failed to create enforcer rules from command line argument", e);
-            }
+        if (commandLineRules == null || commandLineRules.length == 0) {
+            return Optional.empty();
+        }
+
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules");
+
+        for (String rule : commandLineRules) {
+            configuration.addChild(new DefaultPlexusConfiguration(rule));
         }
-        return rules;
+
+        return Optional.of(configuration);
     }
 
     /**
@@ -300,20 +322,6 @@ public class EnforceMojo extends AbstractMojo {
         this.fail = theFail;
     }
 
-    /**
-     * @return the rules
-     */
-    public EnforcerRule[] getRules() {
-        return this.rules;
-    }
-
-    /**
-     * @param theRules the rules to set
-     */
-    public void setRules(EnforcerRule[] theRules) {
-        this.rules = theRules;
-    }
-
     /**
      * @param theFailFast the failFast to set
      */
diff --git a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java
index 23c826c..60d87bf 100644
--- a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java
+++ b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java
@@ -18,6 +18,9 @@
  */
 package org.apache.maven.plugins.enforcer;
 
+import java.util.Arrays;
+import java.util.Collections;
+
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
@@ -26,12 +29,15 @@ import org.apache.maven.plugin.logging.Log;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
+import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 
 import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
 
 /**
  * Exhaustively check the enforcer mojo.
@@ -40,13 +46,16 @@ import static org.junit.jupiter.api.Assertions.*;
  */
 @ExtendWith(MockitoExtension.class)
 @MockitoSettings(strictness = Strictness.LENIENT)
-public class TestEnforceMojo {
+class TestEnforceMojo {
+
+    @Mock
+    private EnforcerRuleManager ruleManager;
 
     @InjectMocks
-    EnforceMojo mojo;
+    private EnforceMojo mojo;
 
     @Test
-    public void testEnforceMojo() throws MojoExecutionException {
+    void testEnforceMojo() throws Exception {
         setupBasics(false);
 
         Log logSpy = setupLogSpy();
@@ -58,10 +67,11 @@ public class TestEnforceMojo {
             System.out.println("Caught Expected Exception:" + e.getLocalizedMessage());
         }
 
-        EnforcerRule[] rules = new EnforcerRule[10];
-        rules[0] = new MockEnforcerRule(true);
-        rules[1] = new MockEnforcerRule(true);
-        mojo.setRules(rules);
+        EnforcerRuleDesc[] rules = new EnforcerRuleDesc[2];
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
+
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         mojo.execute();
 
@@ -86,117 +96,117 @@ public class TestEnforceMojo {
             System.out.println("Caught Expected Exception:" + e.getLocalizedMessage());
         }
 
-        ((MockEnforcerRule) rules[0]).setFailRule(false);
-        ((MockEnforcerRule) rules[1]).setFailRule(false);
+        ((MockEnforcerRule) rules[0].getRule()).setFailRule(false);
+        ((MockEnforcerRule) rules[1].getRule()).setFailRule(false);
         mojo.execute();
     }
 
     @Test
-    public void testCaching() throws MojoExecutionException {
+    void testCaching() throws Exception {
         setupBasics(true);
 
-        MockEnforcerRule[] rules = new MockEnforcerRule[10];
+        EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
         // check that basic caching works.
-        rules[0] = new MockEnforcerRule(false, "", true, true);
-        rules[1] = new MockEnforcerRule(false, "", true, true);
-        mojo.setRules(rules);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         EnforceMojo.cache.clear();
         mojo.execute();
 
-        assertTrue(rules[0].executed, "Expected this rule to be executed.");
-        assertFalse(rules[1].executed, "Expected this rule not to be executed.");
+        assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
+        assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
 
         // check that skip caching works.
-        rules[0] = new MockEnforcerRule(false, "", true, true);
-        rules[1] = new MockEnforcerRule(false, "", true, true);
-        mojo.setRules(rules);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         EnforceMojo.cache.clear();
         mojo.ignoreCache = true;
         mojo.execute();
 
-        assertTrue(rules[0].executed, "Expected this rule to be executed.");
-        assertTrue(rules[1].executed, "Expected this rule to be executed.");
+        assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
+        assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
 
         mojo.ignoreCache = false;
 
         // check that different ids are compared.
-        rules[0] = new MockEnforcerRule(false, "1", true, true);
-        rules[1] = new MockEnforcerRule(false, "2", true, true);
-        rules[2] = new MockEnforcerRule(false, "2", true, true);
-        mojo.setRules(rules);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "2", true, true));
+        rules[2] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "2", true, true));
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         EnforceMojo.cache.clear();
         mojo.execute();
 
-        assertTrue(rules[0].executed, "Expected this rule to be executed.");
-        assertTrue(rules[1].executed, "Expected this rule to be executed.");
-        assertFalse(rules[2].executed, "Expected this rule not to be executed.");
+        assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
+        assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
+        assertFalse(((MockEnforcerRule) rules[2].getRule()).executed, "Expected this rule not to be executed.");
 
         // check that future overrides are working
-        rules[0] = new MockEnforcerRule(false, "1", true, true);
-        rules[1] = new MockEnforcerRule(false, "1", false, true);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", false, true));
         rules[2] = null;
-        mojo.setRules(rules);
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         EnforceMojo.cache.clear();
         mojo.execute();
 
-        assertTrue(rules[0].executed, "Expected this rule to be executed.");
-        assertTrue(rules[1].executed, "Expected this rule to be executed.");
+        assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
+        assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
 
         // check that future isResultValid is used
-        rules[0] = new MockEnforcerRule(false, "1", true, true);
-        rules[1] = new MockEnforcerRule(false, "1", true, false);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, false));
         rules[2] = null;
-        mojo.setRules(rules);
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         EnforceMojo.cache.clear();
         mojo.execute();
 
-        assertTrue(rules[0].executed, "Expected this rule to be executed.");
-        assertTrue(rules[1].executed, "Expected this rule to be executed.");
+        assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
+        assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
     }
 
     @Test
-    public void testCachePersistence1() throws MojoExecutionException {
+    void testCachePersistence1() throws Exception {
         setupBasics(true);
 
-        MockEnforcerRule[] rules = new MockEnforcerRule[10];
+        EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
         // check that basic caching works.
-        rules[0] = new MockEnforcerRule(false, "", true, true);
-        rules[1] = new MockEnforcerRule(false, "", true, true);
-        mojo.setRules(rules);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         EnforceMojo.cache.clear();
         mojo.execute();
 
-        assertTrue(rules[0].executed, "Expected this rule to be executed.");
-        assertFalse(rules[1].executed, "Expected this rule not to be executed.");
+        assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
+        assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
     }
 
     @Test
-    public void testCachePersistence2() throws MojoExecutionException {
+    void testCachePersistence2() throws Exception {
         setupBasics(true);
 
-        MockEnforcerRule[] rules = new MockEnforcerRule[10];
+        EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
         // check that basic caching works.
-        rules[0] = new MockEnforcerRule(false, "", true, true);
-        rules[1] = new MockEnforcerRule(false, "", true, true);
-        mojo.setRules(rules);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         mojo.execute();
 
-        assertFalse(rules[0].executed, "Expected this rule not to be executed.");
-        assertFalse(rules[1].executed, "Expected this rule not to be executed.");
+        assertFalse(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule not to be executed.");
+        assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
     }
 
     @Test
-    public void testCachePersistence3() throws MojoExecutionException {
+    void testCachePersistence3() throws Exception {
         System.gc();
 
         try {
@@ -206,21 +216,21 @@ public class TestEnforceMojo {
 
         setupBasics(true);
 
-        MockEnforcerRule[] rules = new MockEnforcerRule[10];
+        EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
         // check that basic caching works.
-        rules[0] = new MockEnforcerRule(false, "", true, true);
-        rules[1] = new MockEnforcerRule(false, "", true, true);
-        mojo.setRules(rules);
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         mojo.execute();
 
-        assertFalse(rules[0].executed, "Expected this rule not to be executed.");
-        assertFalse(rules[1].executed, "Expected this rule not to be executed.");
+        assertFalse(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule not to be executed.");
+        assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
     }
 
     @Test
-    public void testLoggingOnEnforcerRuleExceptionWithMessage() throws MojoExecutionException, EnforcerRuleException {
+    void testLoggingOnEnforcerRuleExceptionWithMessage() throws Exception {
         // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
         setupBasics(false);
 
@@ -228,9 +238,9 @@ public class TestEnforceMojo {
         EnforcerRuleException ruleException = new EnforcerRuleException("testMessage");
 
         EnforcerRule ruleMock = Mockito.mock(EnforcerRule.class);
-        Mockito.doThrow(ruleException).when(ruleMock).execute(Mockito.any(EnforcerRuleHelper.class));
-
-        mojo.setRules(new EnforcerRule[] {ruleMock});
+        Mockito.doThrow(ruleException).when(ruleMock).execute(any(EnforcerRuleHelper.class));
+        when(ruleManager.createRules(any()))
+                .thenReturn(Collections.singletonList(new EnforcerRuleDesc("mock", ruleMock)));
 
         Log logSpy = setupLogSpy();
 
@@ -238,15 +248,14 @@ public class TestEnforceMojo {
 
         Mockito.verify(logSpy).debug(Mockito.anyString(), Mockito.same(ruleException));
 
-        Mockito.verify(logSpy, Mockito.never()).warn(Mockito.anyString(), Mockito.any(Throwable.class));
+        Mockito.verify(logSpy, Mockito.never()).warn(Mockito.anyString(), any(Throwable.class));
 
         Mockito.verify(logSpy)
                 .warn(Mockito.matches(".* failed with message:" + System.lineSeparator() + ruleException.getMessage()));
     }
 
     @Test
-    public void testLoggingOnEnforcerRuleExceptionWithoutMessage()
-            throws MojoExecutionException, EnforcerRuleException {
+    void testLoggingOnEnforcerRuleExceptionWithoutMessage() throws Exception {
         // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
         setupBasics(false);
 
@@ -255,9 +264,10 @@ public class TestEnforceMojo {
         EnforcerRuleException enforcerRuleException = new EnforcerRuleException(npe.getLocalizedMessage(), npe);
 
         EnforcerRule ruleMock = Mockito.mock(EnforcerRule.class);
-        Mockito.doThrow(enforcerRuleException).when(ruleMock).execute(Mockito.any(EnforcerRuleHelper.class));
+        Mockito.doThrow(enforcerRuleException).when(ruleMock).execute(any(EnforcerRuleHelper.class));
 
-        mojo.setRules(new EnforcerRule[] {ruleMock});
+        when(ruleManager.createRules(any()))
+                .thenReturn(Collections.singletonList(new EnforcerRuleDesc("mock", ruleMock)));
 
         Log logSpy = setupLogSpy();
 
@@ -269,7 +279,7 @@ public class TestEnforceMojo {
     }
 
     @Test
-    public void testFailIfNoTests() throws MojoExecutionException {
+    void testFailIfNoTests() throws MojoExecutionException {
         setupBasics(false);
         mojo.setFailIfNoRules(false);
 
@@ -277,7 +287,7 @@ public class TestEnforceMojo {
 
         mojo.execute();
 
-        Mockito.verify(logSpy).warn(Mockito.eq("No rules are configured."));
+        Mockito.verify(logSpy).warn("No rules are configured.");
         Mockito.verifyNoMoreInteractions(logSpy);
     }