You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2023/02/07 21:24:21 UTC

[maven] branch master updated: [MNG-7686] Speed up by replacing non-pattern #replaceAll() with #replace() or precompiled patterns

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

michaelo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 6e25a2674 [MNG-7686] Speed up by replacing non-pattern #replaceAll() with #replace() or precompiled patterns
6e25a2674 is described below

commit 6e25a2674b3a742bbaee148e9d1359b4495a9fa8
Author: Andrey Bruykhov <an...@gmail.com>
AuthorDate: Tue Feb 7 17:28:03 2023 +0300

    [MNG-7686] Speed up by replacing non-pattern #replaceAll() with #replace() or precompiled patterns
    
    This closes #984
---
 .../maven/profiles/activation/JdkPrefixProfileActivator.java |  2 +-
 .../apache/maven/project/AbstractMavenProjectTestCase.java   |  6 +++---
 .../org/apache/maven/project/ClasspathArtifactResolver.java  |  5 +++--
 .../org/apache/maven/internal/MultilineMessageHelper.java    |  5 ++++-
 .../maven/plugin/PluginParameterExpressionEvaluator.java     |  6 +-----
 .../maven/plugin/PluginParameterExpressionEvaluatorV4.java   |  6 +-----
 .../apache/maven/settings/DefaultMavenSettingsBuilder.java   |  9 +++++----
 .../apache/maven/project/AbstractMavenProjectTestCase.java   |  6 +++---
 .../src/main/java/org/apache/maven/cli/MavenCli.java         |  4 +++-
 .../model/profile/activation/JdkVersionProfileActivator.java | 11 ++++++++---
 .../org/apache/maven/model/transform/ParentXMLFilter.java    |  5 ++++-
 .../maven/model/transform/ReactorDependencyXMLFilter.java    |  5 ++++-
 .../apache/maven/model/transform/RelativePathXMLFilter.java  |  7 ++++++-
 .../org/apache/maven/plugin/descriptor/PluginDescriptor.java |  5 ++++-
 .../repository/internal/RemoteSnapshotMetadataTest.java      |  5 ++++-
 .../maven/settings/validation/DefaultSettingsValidator.java  | 12 ++++++------
 16 files changed, 60 insertions(+), 39 deletions(-)

diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java
index 736f8fdd5..a1e9b9b88 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java
@@ -68,7 +68,7 @@ public class JdkPrefixProfileActivator extends DetectedProfileActivator {
     }
 
     private String convertJdkToMavenVersion(String jdk) {
-        return jdk.replaceAll("_", "-");
+        return jdk.replace("_", "-");
     }
 
     protected String getJdkVersion() {
diff --git a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
index 183d7c645..ca7641cce 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
@@ -22,7 +22,6 @@ import javax.inject.Inject;
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.Arrays;
@@ -81,7 +80,8 @@ public abstract class AbstractMavenProjectTestCase {
         return markerFile.getAbsoluteFile().getParentFile();
     }
 
-    protected static File getFileForClasspathResource(String resource) throws FileNotFoundException {
+    protected static File getFileForClasspathResource(String resource)
+            throws FileNotFoundException, URISyntaxException {
         ClassLoader cloader = Thread.currentThread().getContextClassLoader();
 
         URL resourceUrl = cloader.getResource(resource);
@@ -90,7 +90,7 @@ public abstract class AbstractMavenProjectTestCase {
             throw new FileNotFoundException("Unable to find: " + resource);
         }
 
-        return new File(URI.create(resourceUrl.toString().replaceAll(" ", "%20")));
+        return new File(resourceUrl.toURI());
     }
 
     protected ArtifactRepository getLocalRepository() throws Exception {
diff --git a/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java b/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java
index f22e33df3..ed5584c32 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java
@@ -22,6 +22,7 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -59,8 +60,8 @@ public class ClasspathArtifactResolver implements ArtifactResolver {
                     artifact = artifact.setFile(ProjectClasspathTest.getFileForClasspathResource(
                             ProjectClasspathTest.dir + "transitive-" + scope + "-dep.xml"));
                     result.setArtifact(artifact);
-                } catch (FileNotFoundException e) {
-                    throw new IllegalStateException("Missing test POM for " + artifact);
+                } catch (FileNotFoundException | URISyntaxException e) {
+                    throw new IllegalStateException("Missing test POM for " + artifact, e);
                 }
             } else {
                 result.addException(new ArtifactNotFoundException(artifact, null));
diff --git a/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java b/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java
index 0e52e4c61..9ff2d200e 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java
@@ -20,6 +20,7 @@ package org.apache.maven.internal;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * Helper class to format multiline messages to the console
@@ -29,6 +30,8 @@ public class MultilineMessageHelper {
     private static final int DEFAULT_MAX_SIZE = 65;
     private static final char BOX_CHAR = '*';
 
+    private static final Pattern S_FILTER = Pattern.compile("\\s+");
+
     public static String separatorLine() {
         StringBuilder sb = new StringBuilder(DEFAULT_MAX_SIZE);
         repeat(sb, '*', DEFAULT_MAX_SIZE);
@@ -47,7 +50,7 @@ public class MultilineMessageHelper {
         // lines
         for (String line : lines) {
             sb.setLength(0);
-            String[] words = line.split("\\s+");
+            String[] words = S_FILTER.split(line);
             for (String word : words) {
                 if (sb.length() >= remainder - word.length() - (sb.length() > 0 ? 1 : 0)) {
                     repeat(sb, ' ', remainder - sb.length());
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java
index 8a76960d2..6341acac2 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java
@@ -160,11 +160,7 @@ public class PluginParameterExpressionEvaluator implements TypeAwareExpressionEv
             }
 
             // Was not an expression
-            if (expression.contains("$$")) {
-                return expression.replaceAll("\\$\\$", "\\$");
-            } else {
-                return expression;
-            }
+            return expression.replace("$$", "$");
         }
 
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java
index 488168985..a14a780eb 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java
@@ -163,11 +163,7 @@ public class PluginParameterExpressionEvaluatorV4 implements TypeAwareExpression
             }
 
             // Was not an expression
-            if (expression.contains("$$")) {
-                return expression.replaceAll("\\$\\$", "\\$");
-            } else {
-                return expression;
-            }
+            return expression.replace("$$", "$");
         }
 
         if ("localRepository".equals(expression)) {
diff --git a/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java
index 30bec8ab5..af89dfada 100644
--- a/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java
@@ -119,11 +119,12 @@ public class DefaultMavenSettingsBuilder extends AbstractLogEnabled implements M
                 basedir = System.getProperty("user.dir");
             }
 
-            basedir = basedir.replaceAll("\\\\", "/");
-            basedir = basedir.replaceAll("\\$", "\\\\\\$");
+            basedir = basedir.replace("\\", "/");
+            basedir = basedir.replace("$", "\\$");
 
-            path = pathPattern.replaceAll("\\$\\{" + basedirSysProp + "\\}", basedir);
-            path = path.replaceAll("\\\\", "/");
+            // basedirSysProp is non regexp and basedir too
+            path = pathPattern.replace("${" + basedirSysProp + "}", basedir);
+            path = path.replace("\\", "/");
             // ---------------------------------------------------------------------------------
             // I'm not sure if this last regexp was really intended to disallow the usage of
             // network paths as user.home directory. Unfortunately it did. I removed it and
diff --git a/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java b/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
index 0d163d582..ced697657 100644
--- a/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
+++ b/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
@@ -22,7 +22,6 @@ import javax.inject.Inject;
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.Arrays;
@@ -79,7 +78,8 @@ public abstract class AbstractMavenProjectTestCase {
         return markerFile.getAbsoluteFile().getParentFile();
     }
 
-    protected static File getFileForClasspathResource(String resource) throws FileNotFoundException {
+    protected static File getFileForClasspathResource(String resource)
+            throws FileNotFoundException, URISyntaxException {
         ClassLoader cloader = Thread.currentThread().getContextClassLoader();
 
         URL resourceUrl = cloader.getResource(resource);
@@ -88,7 +88,7 @@ public abstract class AbstractMavenProjectTestCase {
             throw new FileNotFoundException("Unable to find: " + resource);
         }
 
-        return new File(URI.create(resourceUrl.toString().replaceAll(" ", "%20")));
+        return new File(resourceUrl.toURI());
     }
 
     protected ArtifactRepository getLocalRepository() throws Exception {
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index cf9947545..fa38d0b84 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -175,6 +175,8 @@ public class MavenCli {
 
     private CLIManager cliManager;
 
+    private static final Pattern NEXT_LINE = Pattern.compile("\r?\n");
+
     public MavenCli() {
         this(null);
     }
@@ -985,7 +987,7 @@ public class MavenCli {
             }
         }
 
-        String[] lines = msg.split("(\r\n)|(\r)|(\n)");
+        String[] lines = NEXT_LINE.split(msg);
         String currentColor = "";
 
         for (int i = 0; i < lines.length; i++) {
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java
index 0f3f7d1cd..fbaa19bc0 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java
@@ -24,6 +24,7 @@ import javax.inject.Singleton;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.regex.Pattern;
 
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.Profile;
@@ -43,6 +44,10 @@ import org.apache.maven.model.profile.ProfileActivationContext;
 @Singleton
 public class JdkVersionProfileActivator implements ProfileActivator {
 
+    private static final Pattern FILTER_1 = Pattern.compile("[^0-9._-]");
+    private static final Pattern FILTER_2 = Pattern.compile("[._-]");
+    private static final Pattern FILTER_3 = Pattern.compile("\\."); // used for split now
+
     @Override
     public boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
@@ -110,10 +115,10 @@ public class JdkVersionProfileActivator implements ProfileActivator {
             return isLeft ? 1 : -1;
         }
 
-        value = value.replaceAll("[^0-9\\.\\-\\_]", "");
+        value = FILTER_1.matcher(value).replaceAll("");
 
-        List<String> valueTokens = new ArrayList<>(Arrays.asList(value.split("[\\.\\-\\_]")));
-        List<String> rangeValueTokens = new ArrayList<>(Arrays.asList(rangeValue.value.split("\\.")));
+        List<String> valueTokens = new ArrayList<>(Arrays.asList(FILTER_2.split(value)));
+        List<String> rangeValueTokens = new ArrayList<>(Arrays.asList(FILTER_3.split(rangeValue.value)));
 
         addZeroTokens(valueTokens, 3);
         addZeroTokens(rangeValueTokens, 3);
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
index 7f525e167..37160fd35 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
+import java.util.regex.Pattern;
 
 import org.apache.maven.model.transform.pull.NodeBufferingParser;
 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
@@ -47,6 +48,8 @@ class ParentXMLFilter extends NodeBufferingParser {
 
     private final Path projectPath;
 
+    private static final Pattern S_FILTER = Pattern.compile("\\s+");
+
     /**
      * @param relativePathMapper
      */
@@ -73,7 +76,7 @@ class ParentXMLFilter extends NodeBufferingParser {
                 hasVersion |= "version".equals(tagName);
                 hasRelativePath |= "relativePath".equals(tagName);
             } else if (event.event == TEXT) {
-                if (event.text.matches("\\s+")) {
+                if (S_FILTER.matcher(event.text).matches()) {
                     if (whitespaceAfterParentStart.isEmpty()) {
                         whitespaceAfterParentStart = event.text;
                     }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
index 359217b23..186383f1c 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
@@ -20,6 +20,7 @@ package org.apache.maven.model.transform;
 
 import java.util.List;
 import java.util.function.BiFunction;
+import java.util.regex.Pattern;
 
 import org.apache.maven.model.transform.pull.NodeBufferingParser;
 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
@@ -34,6 +35,8 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 public class ReactorDependencyXMLFilter extends NodeBufferingParser {
     private final BiFunction<String, String, String> reactorVersionMapper;
 
+    private static final Pattern S_FILTER = Pattern.compile("\\s+");
+
     public ReactorDependencyXMLFilter(
             XmlPullParser xmlPullParser, BiFunction<String, String, String> reactorVersionMapper) {
         super(xmlPullParser, "dependency");
@@ -53,7 +56,7 @@ public class ReactorDependencyXMLFilter extends NodeBufferingParser {
                 tagName = event.name;
                 hasVersion |= "version".equals(tagName);
             } else if (event.event == TEXT) {
-                if (event.text.matches("\\s+")) {
+                if (S_FILTER.matcher(event.text).matches()) {
                     if (dependencyWhitespace.isEmpty()) {
                         dependencyWhitespace = event.text;
                     }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
index 181e2eb9b..f785ab349 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
@@ -19,6 +19,7 @@
 package org.apache.maven.model.transform;
 
 import java.util.List;
+import java.util.regex.Pattern;
 
 import org.apache.maven.model.transform.pull.NodeBufferingParser;
 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
@@ -32,6 +33,8 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParser;
  */
 public class RelativePathXMLFilter extends NodeBufferingParser {
 
+    private static final Pattern S_FILTER = Pattern.compile("\\s+");
+
     public RelativePathXMLFilter(XmlPullParser xmlPullParser) {
         super(xmlPullParser, "parent");
     }
@@ -42,7 +45,9 @@ public class RelativePathXMLFilter extends NodeBufferingParser {
         for (Event event : buffer) {
             if (event.event == START_TAG && "relativePath".equals(event.name)) {
                 skip = true;
-                if (prev != null && prev.event == TEXT && prev.text.matches("\\s+")) {
+                if (prev != null
+                        && prev.event == TEXT
+                        && S_FILTER.matcher(prev.text).matches()) {
                     prev = null;
                 }
                 event = null;
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
index 92654a75d..1247e7dd4 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
@@ -30,6 +30,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.ArtifactUtils;
@@ -49,6 +50,8 @@ public class PluginDescriptor extends ComponentSetDescriptor implements Cloneabl
 
     private static final String LIFECYCLE_DESCRIPTOR = "META-INF/maven/lifecycle.xml";
 
+    private static final Pattern PATTERN_FILTER_1 = Pattern.compile("-?(maven|plugin)-?");
+
     private String groupId;
 
     private String artifactId;
@@ -166,7 +169,7 @@ public class PluginDescriptor extends ComponentSetDescriptor implements Cloneabl
         if ("maven-plugin-plugin".equals(artifactId)) {
             return "plugin";
         } else {
-            return artifactId.replaceAll("-?maven-?", "").replaceAll("-?plugin-?", "");
+            return PATTERN_FILTER_1.matcher(artifactId).replaceAll("");
         }
     }
 
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java
index 3d2271c13..a4db9102b 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java
@@ -25,6 +25,7 @@ import java.util.GregorianCalendar;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.maven.artifact.repository.metadata.Metadata;
 import org.eclipse.aether.artifact.DefaultArtifact;
@@ -37,6 +38,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 public class RemoteSnapshotMetadataTest {
     private Locale defaultLocale;
 
+    private static final Pattern DATE_FILTER = Pattern.compile("\\..*");
+
     @BeforeEach
     public void setLocaleToUseBuddhistCalendar() {
         defaultLocale = Locale.getDefault();
@@ -66,7 +69,7 @@ public class RemoteSnapshotMetadataTest {
         String dateAfter = gregorianDate();
 
         String ts = metadata.metadata.getVersioning().getSnapshot().getTimestamp();
-        String datePart = ts.replaceAll("\\..*", "");
+        String datePart = DATE_FILTER.matcher(ts).replaceAll("");
 
         /* Allow for this test running across midnight */
         Set<String> expected = new HashSet<>(Arrays.asList(dateBefore, dateAfter));
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
index 11ec66d61..3706775f7 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
@@ -24,6 +24,7 @@ import javax.inject.Singleton;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.maven.settings.Mirror;
 import org.apache.maven.settings.Profile;
@@ -42,11 +43,10 @@ import org.codehaus.plexus.util.StringUtils;
 @Singleton
 public class DefaultSettingsValidator implements SettingsValidator {
 
-    private static final String ID_REGEX = "[A-Za-z0-9_\\-.]+";
+    private static final String ID = "[\\w.-]+";
+    private static final Pattern ID_REGEX = Pattern.compile(ID);
 
-    private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*";
-
-    private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS;
+    private static final String ILLEGAL_REPO_ID_CHARS = "\\/:\"<>|?*"; // ILLEGAL_FS_CHARS
 
     @Override
     public void validate(Settings settings, SettingsProblemCollector problems) {
@@ -63,13 +63,13 @@ public class DefaultSettingsValidator implements SettingsValidator {
                 if (StringUtils.isBlank(pluginGroup)) {
                     addViolation(
                             problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null, "must not be empty");
-                } else if (!pluginGroup.matches(ID_REGEX)) {
+                } else if (!ID_REGEX.matcher(pluginGroup).matches()) {
                     addViolation(
                             problems,
                             Severity.ERROR,
                             "pluginGroups.pluginGroup[" + i + "]",
                             null,
-                            "must denote a valid group id and match the pattern " + ID_REGEX);
+                            "must denote a valid group id and match the pattern " + ID);
                 }
             }
         }