This is an automated email from the ASF dual-hosted git repository. kwin pushed a commit to branch bugfix/quote-regex-in-simplerelocator in repository https://gitbox.apache.org/repos/asf/maven-shade-plugin.git
commit d7c92ecf5018a175c67b81e8e6e5d7e656b7bb0d Author: Konrad Windszus <[email protected]> AuthorDate: Thu Mar 5 11:37:07 2026 +0100 Quote text within regular expression patterns correctly Use compiled RegEx patterns to speed up replacement Clarify which pattern fields allow which wildcard (follow which syntax) This closes #790 --- .../plugins/shade/relocation/SimpleRelocator.java | 76 +++++++++++++++------- .../shade/relocation/SimpleRelocatorTest.java | 4 ++ 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/apache/maven/plugins/shade/relocation/SimpleRelocator.java b/src/main/java/org/apache/maven/plugins/shade/relocation/SimpleRelocator.java index b801fd0..b1d1e9a 100644 --- a/src/main/java/org/apache/maven/plugins/shade/relocation/SimpleRelocator.java +++ b/src/main/java/org/apache/maven/plugins/shade/relocation/SimpleRelocator.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; import org.codehaus.plexus.util.SelectorUtils; @@ -52,20 +53,34 @@ public class SimpleRelocator implements Relocator { + "|" + "([{}(=;,]|\\*/) $"); - private final String pattern; + /** plain text, no wildcards, always refer to classes, not paths */ + private final String originalPattern; - private final String pathPattern; + /** plain text, no wildcards, always refer to paths not classes */ + private final String originalPathPattern; + private final Pattern regExPattern; + + private final Pattern regExPathPattern; + + // replacement (no wildcards) private final String shadedPattern; + // replacement (no wildcards) private final String shadedPathPattern; + // only ant patterns (used with SelectorUtils.matchPath), must not start with "%ant[" prefix, always refer to paths + // not classes private final Set<String> includes; + // only ant patterns (used with SelectorUtils.matchPath), must not start with "%ant[" prefix, always refer to paths + // not classes private final Set<String> excludes; + // prefix (no wildcards), derived from excludes private final Set<String> sourcePackageExcludes = new LinkedHashSet<>(); + // prefix (no wildcards), derived from excludes private final Set<String> sourcePathExcludes = new LinkedHashSet<>(); private final boolean rawString; @@ -77,28 +92,28 @@ public class SimpleRelocator implements Relocator { public SimpleRelocator( String patt, String shadedPattern, List<String> includes, List<String> excludes, boolean rawString) { this.rawString = rawString; - if (rawString) { - this.pathPattern = patt; + originalPathPattern = patt; this.shadedPathPattern = shadedPattern; - this.pattern = null; // not used for raw string relocator + originalPattern = null; // not used for raw string relocator this.shadedPattern = null; // not used for raw string relocator } else { if (patt == null) { - this.pattern = ""; - this.pathPattern = ""; + // what does this mean? + originalPattern = null; + originalPathPattern = null; } else { - this.pattern = patt.replace('/', '.'); - this.pathPattern = patt.replace('.', '/'); + originalPattern = patt.replace('/', '.'); + originalPathPattern = patt.replace('.', '/'); } if (shadedPattern != null) { this.shadedPattern = shadedPattern.replace('/', '.'); this.shadedPathPattern = shadedPattern.replace('.', '/'); } else { - this.shadedPattern = "hidden." + this.pattern; - this.shadedPathPattern = "hidden/" + this.pathPattern; + this.shadedPattern = "hidden." + originalPattern; + this.shadedPathPattern = "hidden/" + originalPathPattern; } } @@ -118,17 +133,26 @@ public class SimpleRelocator implements Relocator { // Create exclude pattern sets for sources for (String exclude : this.excludes) { // Excludes should be subpackages of the global pattern - if (exclude.startsWith(pattern)) { + if (exclude.startsWith(originalPattern)) { sourcePackageExcludes.add( - exclude.substring(pattern.length()).replaceFirst("[.][*]$", "")); + exclude.substring(originalPattern.length()).replaceFirst("[.][*]$", "")); } // Excludes should be subpackages of the global pattern - if (exclude.startsWith(pathPattern)) { + if (exclude.startsWith(originalPathPattern)) { sourcePathExcludes.add( - exclude.substring(pathPattern.length()).replaceFirst("[/][*]$", "")); + exclude.substring(originalPathPattern.length()).replaceFirst("[/][*]$", "")); } } } + // raw strings are already treated as regex patterns, so don't quote them, otherwise the regex won't work as + // intended + if (!rawString) { + regExPattern = originalPattern != null ? Pattern.compile(Pattern.quote(originalPattern)) : null; + regExPathPattern = originalPathPattern != null ? Pattern.compile(Pattern.quote(originalPathPattern)) : null; + } else { + this.regExPattern = originalPattern != null ? Pattern.compile(originalPattern) : null; + this.regExPathPattern = originalPathPattern != null ? Pattern.compile(originalPathPattern) : null; + } } private static Set<String> normalizePatterns(Collection<String> patterns) { @@ -177,7 +201,7 @@ public class SimpleRelocator implements Relocator { @Override public boolean canRelocatePath(String path) { if (rawString) { - return Pattern.compile(pathPattern).matcher(path).find(); + return regExPathPattern.matcher(path).find(); } if (path.endsWith(".class")) { @@ -190,7 +214,13 @@ public class SimpleRelocator implements Relocator { path = path.substring(1); } - return isIncluded(path) && !isExcluded(path) && path.startsWith(pathPattern); + if (isIncluded(path) && !isExcluded(path)) { + Matcher matcher = regExPathPattern.matcher(path); + if (matcher.find()) { + return matcher.start() == 0; + } + } + return false; } @Override @@ -201,20 +231,20 @@ public class SimpleRelocator implements Relocator { @Override public String relocatePath(String path) { if (rawString) { - return path.replaceAll(pathPattern, shadedPathPattern); + return regExPathPattern.matcher(path).replaceAll(shadedPathPattern); } else { - return path.replaceFirst(pathPattern, shadedPathPattern); + return regExPathPattern.matcher(path).replaceFirst(shadedPathPattern); } } @Override public String relocateClass(String input) { - return rawString ? input : input.replaceFirst(pattern, shadedPattern); + return rawString ? input : regExPattern.matcher(input).replaceFirst(shadedPattern); } @Override public String relocateAllClasses(String input) { - return rawString ? input : input.replaceAll(pattern, shadedPattern); + return rawString ? input : regExPattern.matcher(input).replaceAll(shadedPattern); } @Override @@ -222,8 +252,8 @@ public class SimpleRelocator implements Relocator { if (rawString) { return sourceContent; } - sourceContent = shadeSourceWithExcludes(sourceContent, pattern, shadedPattern, sourcePackageExcludes); - return shadeSourceWithExcludes(sourceContent, pathPattern, shadedPathPattern, sourcePathExcludes); + sourceContent = shadeSourceWithExcludes(sourceContent, originalPattern, shadedPattern, sourcePackageExcludes); + return shadeSourceWithExcludes(sourceContent, originalPathPattern, shadedPathPattern, sourcePathExcludes); } private String shadeSourceWithExcludes( diff --git a/src/test/java/org/apache/maven/plugins/shade/relocation/SimpleRelocatorTest.java b/src/test/java/org/apache/maven/plugins/shade/relocation/SimpleRelocatorTest.java index 44afee3..45f6601 100644 --- a/src/test/java/org/apache/maven/plugins/shade/relocation/SimpleRelocatorTest.java +++ b/src/test/java/org/apache/maven/plugins/shade/relocation/SimpleRelocatorTest.java @@ -155,6 +155,8 @@ public class SimpleRelocatorTest { relocator = new SimpleRelocator("org.foo", "private.stuff", null, null); assertEquals("private.stuff.bar.Class", relocator.relocateClass("org.foo.bar.Class")); + // make sure that "." does not match "x" in "orgxfoo.bar.Class" + assertEquals("orgxfoo.bar.Class", relocator.relocateClass("orgxfoo.bar.Class")); } @Test @@ -170,6 +172,8 @@ public class SimpleRelocatorTest { assertEquals( "private.stuff.bar.Class, private.stuff.bar.Class and private.stuff.bar.Class", relocator.relocateAllClasses("org.foo.bar.Class, private.stuff.bar.Class and org.foo.bar.Class")); + // make sure that "." does not match "x" in "orgxfoo.bar.Class" + assertEquals("orgxfoo.bar.Class", relocator.relocateClass("orgxfoo.bar.Class")); } @Test
