Skip to content

Commit da69608

Browse files
kriegaexhboutemy
authored andcommitted
[MSHADE-252] Make source shading respect package/class name excludes
Fixes MSHADE-252. Until now, there was a naive global search + replace for mapping '<pattern>' to '<shadedPattern>', even if the corresponding packages are to be ignored. This works for binary JARs, but was completely broken for source JARs. See also my related comment in MSHADE-252: https://issues.apache.org/jira/browse/MSHADE-252?focusedCommentId=17314377&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-17314377 With this fix, on the one hand string replacement in source files works for both "dotty" strings like "my.package.name.Foo" and "slashy" ones like "/my/package/name/resource.properties". On the other hand, source files are now being parsed '<pattern>' match by match and for each match the excludes list will be checked and replacements only performed if the corresponding matched package name is not on the excludes list. This is of course slower than just a raw 'replaceAll(..)', but it produces correct results.
1 parent cf24c1a commit da69608

File tree

2 files changed

+122
-1
lines changed

2 files changed

+122
-1
lines changed

src/main/java/org/apache/maven/plugins/shade/relocation/SimpleRelocator.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public class SimpleRelocator
4747

4848
private final Set<String> excludes;
4949

50+
private final Set<String> sourcePackageExcludes = new LinkedHashSet<>();
51+
52+
private final Set<String> sourcePathExcludes = new LinkedHashSet<>();
53+
5054
private final boolean rawString;
5155

5256
public SimpleRelocator( String patt, String shadedPattern, List<String> includes, List<String> excludes )
@@ -105,6 +109,24 @@ public SimpleRelocator( String patt, String shadedPattern, List<String> includes
105109
{
106110
this.excludes.addAll( excludes );
107111
}
112+
113+
if ( !rawString && this.excludes != null )
114+
{
115+
// Create exclude pattern sets for sources
116+
for ( String exclude : this.excludes )
117+
{
118+
// Excludes should be subpackages of the global pattern
119+
if ( exclude.startsWith( pattern ) )
120+
{
121+
sourcePackageExcludes.add( exclude.substring( pattern.length() ).replaceFirst( "[.][*]$", "" ) );
122+
}
123+
// Excludes should be subpackages of the global pattern
124+
else if ( exclude.startsWith( pathPattern ) )
125+
{
126+
sourcePathExcludes.add( exclude.substring( pathPattern.length() ).replaceFirst( "[/][*]$", "" ) );
127+
}
128+
}
129+
}
108130
}
109131

110132
private static Set<String> normalizePatterns( Collection<String> patterns )
@@ -214,7 +236,39 @@ public String applyToSourceContent( String sourceContent )
214236
}
215237
else
216238
{
217-
return sourceContent.replaceAll( "\\b" + pattern, shadedPattern );
239+
sourceContent = shadeSourceWithExcludes( sourceContent, pattern, shadedPattern, sourcePackageExcludes );
240+
return shadeSourceWithExcludes( sourceContent, pathPattern, shadedPathPattern, sourcePathExcludes );
241+
}
242+
}
243+
244+
private String shadeSourceWithExcludes( String sourceContent, String patternFrom, String patternTo,
245+
Set<String> excludedPatterns )
246+
{
247+
// Usually shading makes package names a bit longer, so make buffer 10% bigger than original source
248+
StringBuilder shadedSourceContent = new StringBuilder( sourceContent.length() * 11 / 10 );
249+
boolean isFirstSnippet = true;
250+
// Make sure that search pattern starts at word boundary and we look for literal ".", not regex jokers
251+
for ( String snippet : sourceContent.split( "\\b" + patternFrom.replace( ".", "[.]" ) ) )
252+
{
253+
boolean doExclude = false;
254+
for ( String excludedPattern : excludedPatterns )
255+
{
256+
if ( snippet.startsWith( excludedPattern ) )
257+
{
258+
doExclude = true;
259+
break;
260+
}
261+
}
262+
if ( isFirstSnippet )
263+
{
264+
shadedSourceContent.append( snippet );
265+
isFirstSnippet = false;
266+
}
267+
else
268+
{
269+
shadedSourceContent.append( doExclude ? patternFrom : patternTo ).append( snippet );
270+
}
218271
}
272+
return shadedSourceContent.toString();
219273
}
220274
}

src/test/java/org/apache/maven/plugins/shade/relocation/SimpleRelocatorTest.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,71 @@ public void testRelocateMavenFiles()
188188
assertTrue( relocator.canRelocatePath( "META-INF/maven/com-foo-bar/artifactId/pom.xml" ) );
189189

190190
}
191+
192+
private static final String sourceFile =
193+
"package org.apache.maven.hello;\n" +
194+
"\n" +
195+
"import foo.bar.Bar;\n" +
196+
"import zot.baz.Baz;\n" +
197+
"import org.apache.maven.exclude1.Ex1;\n" +
198+
"import org.apache.maven.exclude1.a.b.Ex1AB;\n" +
199+
"import org.apache.maven.sub.exclude2.Ex2;\n" +
200+
"import org.apache.maven.sub.exclude2.c.d.Ex2CD;\n" +
201+
"import org.apache.maven.In;\n" +
202+
"import org.apache.maven.e.InE;\n" +
203+
"import org.apache.maven.f.g.InFG;\n" +
204+
"\n" +
205+
"public class MyClass {\n" +
206+
" private org.apache.maven.exclude1.x.X myX;\n" +
207+
" private org.apache.maven.h.H;\n" +
208+
"\n" +
209+
" public void doSomething() {\n" +
210+
" String noRelocation = \"NoWordBoundaryXXXorg.apache.maven.In\";\n" +
211+
" String relocationPackage = \"org.apache.maven.In\";\n" +
212+
" String relocationPath = \"org/apache/maven/In\";\n" +
213+
" }\n" +
214+
"}\n";
215+
216+
private static final String relocatedFile =
217+
"package com.acme.maven.hello;\n" +
218+
"\n" +
219+
"import foo.bar.Bar;\n" +
220+
"import zot.baz.Baz;\n" +
221+
"import org.apache.maven.exclude1.Ex1;\n" +
222+
"import org.apache.maven.exclude1.a.b.Ex1AB;\n" +
223+
"import org.apache.maven.sub.exclude2.Ex2;\n" +
224+
"import org.apache.maven.sub.exclude2.c.d.Ex2CD;\n" +
225+
"import com.acme.maven.In;\n" +
226+
"import com.acme.maven.e.InE;\n" +
227+
"import com.acme.maven.f.g.InFG;\n" +
228+
"\n" +
229+
"public class MyClass {\n" +
230+
" private org.apache.maven.exclude1.x.X myX;\n" +
231+
" private com.acme.maven.h.H;\n" +
232+
"\n" +
233+
" public void doSomething() {\n" +
234+
" String noRelocation = \"NoWordBoundaryXXXorg.apache.maven.In\";\n" +
235+
" String relocationPackage = \"com.acme.maven.In\";\n" +
236+
" String relocationPath = \"com/acme/maven/In\";\n" +
237+
" }\n" +
238+
"}\n";
239+
240+
@Test
241+
public void testRelocateSourceWithExcludesRaw()
242+
{
243+
SimpleRelocator relocator = new SimpleRelocator( "org.apache.maven", "com.acme.maven",
244+
Arrays.asList( "foo.bar", "zot.baz" ),
245+
Arrays.asList( "irrelevant.exclude", "org.apache.maven.exclude1", "org.apache.maven.sub.exclude2" ),
246+
true );
247+
assertEquals( sourceFile, relocator.applyToSourceContent( sourceFile ) );
248+
}
249+
250+
@Test
251+
public void testRelocateSourceWithExcludes()
252+
{
253+
SimpleRelocator relocator = new SimpleRelocator( "org.apache.maven", "com.acme.maven",
254+
Arrays.asList( "foo.bar", "zot.baz" ),
255+
Arrays.asList( "irrelevant.exclude", "org.apache.maven.exclude1", "org.apache.maven.sub.exclude2" ) );
256+
assertEquals( relocatedFile, relocator.applyToSourceContent( sourceFile ) );
257+
}
191258
}

0 commit comments

Comments
 (0)