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 083957fd..cc7406dd 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 @@ -25,6 +25,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -121,7 +122,7 @@ public SimpleRelocator( String patt, String shadedPattern, List includes sourcePackageExcludes.add( exclude.substring( pattern.length() ).replaceFirst( "[.][*]$", "" ) ); } // Excludes should be subpackages of the global pattern - else if ( exclude.startsWith( pathPattern ) ) + if ( exclude.startsWith( pathPattern ) ) { sourcePathExcludes.add( exclude.substring( pathPattern.length() ).replaceFirst( "[/][*]$", "" ) ); } @@ -230,15 +231,13 @@ public String relocateClass( String clazz ) public String applyToSourceContent( String sourceContent ) { - if ( rawString ) - { - return sourceContent; - } - else + if ( !rawString ) { sourceContent = shadeSourceWithExcludes( sourceContent, pattern, shadedPattern, sourcePackageExcludes ); - return shadeSourceWithExcludes( sourceContent, pathPattern, shadedPathPattern, sourcePathExcludes ); + sourceContent = shadeSourceWithExcludes( sourceContent, pathPattern, shadedPathPattern, + sourcePathExcludes ); } + return sourceContent; } private String shadeSourceWithExcludes( String sourceContent, String patternFrom, String patternTo, @@ -246,29 +245,57 @@ private String shadeSourceWithExcludes( String sourceContent, String patternFrom { // Usually shading makes package names a bit longer, so make buffer 10% bigger than original source StringBuilder shadedSourceContent = new StringBuilder( sourceContent.length() * 11 / 10 ); - boolean isFirstSnippet = true; - // Make sure that search pattern starts at word boundary and we look for literal ".", not regex jokers - for ( String snippet : sourceContent.split( "\\b" + patternFrom.replace( ".", "[.]" ) ) ) + + int index = 0; + // Make sure that we look for literal ".", not regex jokers + Matcher matcher = Pattern.compile( patternFrom.replace( ".", "[.]" ) ).matcher( sourceContent ); + while ( matcher.find( index ) ) { boolean doExclude = false; - for ( String excludedPattern : excludedPatterns ) + shadedSourceContent.append( sourceContent.substring( index, matcher.start() ) ); + index = matcher.end(); + if ( matcher.start() > 1 ) { - if ( snippet.startsWith( excludedPattern ) ) + char before = sourceContent.charAt( matcher.start() - 1 ); + /* + * Exclude the following situation + * Pattern: "io" + * Content: java.io.IOException; + * Content: private String myException; + * We found "io" in "java.io" or myException, which should be excluded + */ + if ( '.' == before || Character.isLetter( before ) ) { doExclude = true; - break; } } - if ( isFirstSnippet ) + char after = sourceContent.charAt( matcher.end() ); + /* + * If next char is not a "." nor a "/" we need to exclude + * Pattern: io + * Content: private String ioInput + * Content: String io, val; + * We found io in "ioInput" or "io,", which should be excluded + */ + if ( '.' != after && '/' != after ) { - shadedSourceContent.append( snippet ); - isFirstSnippet = false; - } - else + doExclude = true; + } + + if ( !doExclude ) { - shadedSourceContent.append( doExclude ? patternFrom : patternTo ).append( snippet ); + for ( String excludedPattern : excludedPatterns ) + { + if ( sourceContent.startsWith( excludedPattern, index ) ) + { + doExclude = true; + break; + } + } } + shadedSourceContent.append( doExclude ? patternFrom : patternTo ); } + shadedSourceContent.append( sourceContent.substring( index ) ); return shadedSourceContent.toString(); } } 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 2934d0d0..b52fd9e6 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 @@ -201,12 +201,15 @@ public void testRelocateMavenFiles() "import org.apache.maven.In;\n" + "import org.apache.maven.e.InE;\n" + "import org.apache.maven.f.g.InFG;\n" + + "import java.io.IOException;\n" + "\n" + "public class MyClass {\n" + " private org.apache.maven.exclude1.x.X myX;\n" + " private org.apache.maven.h.H;\n" + + " private String ioInput;\n" + "\n" + " public void doSomething() {\n" + + " String io, val;\n" + " String noRelocation = \"NoWordBoundaryXXXorg.apache.maven.In\";\n" + " String relocationPackage = \"org.apache.maven.In\";\n" + " String relocationPath = \"org/apache/maven/In\";\n" + @@ -225,12 +228,15 @@ public void testRelocateMavenFiles() "import com.acme.maven.In;\n" + "import com.acme.maven.e.InE;\n" + "import com.acme.maven.f.g.InFG;\n" + + "import java.io.IOException;\n" + "\n" + "public class MyClass {\n" + " private org.apache.maven.exclude1.x.X myX;\n" + " private com.acme.maven.h.H;\n" + + " private String ioInput;\n" + "\n" + " public void doSomething() {\n" + + " String io, val;\n" + " String noRelocation = \"NoWordBoundaryXXXorg.apache.maven.In\";\n" + " String relocationPackage = \"com.acme.maven.In\";\n" + " String relocationPath = \"com/acme/maven/In\";\n" + @@ -255,4 +261,15 @@ public void testRelocateSourceWithExcludes() Arrays.asList( "irrelevant.exclude", "org.apache.maven.exclude1", "org.apache.maven.sub.exclude2" ) ); assertEquals( relocatedFile, relocator.applyToSourceContent( sourceFile ) ); } + + @Test + public void testRelocateSourceWithMultipleRelocators() + { + SimpleRelocator relocator = new SimpleRelocator( "org.apache.maven", "com.acme.maven", + Arrays.asList( "foo.bar", "zot.baz" ), + Arrays.asList( "irrelevant.exclude", "org.apache.maven.exclude1", "org.apache.maven.sub.exclude2" ) ); + + SimpleRelocator relocatorPackage = new SimpleRelocator( "io", "shaded.io", null, null); + assertEquals( relocatedFile, relocatorPackage.applyToSourceContent( relocator.applyToSourceContent( sourceFile ) ) ); + } }