View Javadoc
1   package org.apache.maven.plugins.shade.mojo;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static java.util.Arrays.asList;
23  import static java.util.Collections.singletonList;
24  import static org.mockito.Mockito.mock;
25  import static org.mockito.Mockito.when;
26  
27  import java.io.File;
28  import java.lang.reflect.Field;
29  import java.lang.reflect.Method;
30  import java.net.URL;
31  import java.net.URLClassLoader;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.LinkedHashSet;
35  import java.util.List;
36  import java.util.Set;
37  
38  import org.apache.maven.artifact.Artifact;
39  import org.apache.maven.artifact.DefaultArtifact;
40  import org.apache.maven.artifact.handler.ArtifactHandler;
41  import org.apache.maven.artifact.versioning.VersionRange;
42  import org.apache.maven.execution.MavenSession;
43  import org.apache.maven.plugins.shade.ShadeRequest;
44  import org.apache.maven.plugins.shade.Shader;
45  import org.apache.maven.plugins.shade.filter.Filter;
46  import org.apache.maven.plugins.shade.relocation.Relocator;
47  import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
48  import org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformer;
49  import org.apache.maven.plugins.shade.resource.ManifestResourceTransformer;
50  import org.apache.maven.plugins.shade.resource.ResourceTransformer;
51  import org.apache.maven.project.MavenProject;
52  import org.apache.maven.project.ProjectBuildingRequest;
53  import org.apache.maven.shared.transfer.artifact.ArtifactCoordinate;
54  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver;
55  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult;
56  import org.codehaus.plexus.ContainerConfiguration;
57  import org.codehaus.plexus.PlexusConstants;
58  import org.codehaus.plexus.PlexusTestCase;
59  
60  /**
61   * @author Jason van Zyl
62   * @author Mauro Talevi
63   */
64  public class ShadeMojoTest
65      extends PlexusTestCase
66  {
67      @Override
68      protected void customizeContainerConfiguration(final ContainerConfiguration configuration) {
69          configuration.setClassPathScanning(PlexusConstants.SCANNING_INDEX);
70      }
71  
72      public void testManifestTransformerSelection() throws Exception
73      {
74          final ShadeMojo mojo = new ShadeMojo();
75          final Method m = ShadeMojo.class.getDeclaredMethod("toResourceTransformers", String.class, List.class);
76          m.setAccessible(true);
77  
78          final ManifestResourceTransformer defaultTfr = new ManifestResourceTransformer()
79          {
80              @Override
81              public String toString() // when test fails junit does a toString so easier to read errors this way
82              {
83                  return "default";
84              }
85          };
86          final ManifestResourceTransformer testsTfr1 = new ManifestResourceTransformer()
87          {
88              @Override
89              public String toString()
90              {
91                  return "t1";
92              }
93          };
94          testsTfr1.setForShade("tests");
95          final ManifestResourceTransformer testsTfr2 = new ManifestResourceTransformer()
96          {
97              @Override
98              public String toString()
99              {
100                 return "t2";
101             }
102         };
103         testsTfr2.setForShade("tests");
104 
105         assertEquals(
106                 singletonList( defaultTfr ),
107                 m.invoke( mojo, "jar", asList( defaultTfr, testsTfr1, testsTfr2 ) ));
108         assertEquals(
109                 asList( testsTfr1, testsTfr2 ),
110                 m.invoke( mojo, "tests", asList( defaultTfr, testsTfr1, testsTfr2 ) ));
111         assertEquals(
112                 asList( testsTfr1, testsTfr2 ),
113                 m.invoke( mojo, "tests", asList( testsTfr1, defaultTfr, testsTfr2 ) ));
114         assertEquals(
115                 asList( testsTfr1, testsTfr2 ),
116                 m.invoke( mojo, "tests", asList( testsTfr1, testsTfr2, defaultTfr ) ));
117     }
118 
119     public void testShaderWithDefaultShadedPattern()
120         throws Exception
121     {
122         shaderWithPattern( null, new File( "target/foo-default.jar" ) );
123     }
124 
125     public void testShaderWithCustomShadedPattern()
126         throws Exception
127     {
128         shaderWithPattern( "org/shaded/plexus/util", new File( "target/foo-custom.jar" ) );
129     }
130 
131     public void testShaderWithExclusions()
132         throws Exception
133     {
134         File jarFile = new File( getBasedir(), "target/unit/foo-bar.jar" );
135 
136         Shader s = lookup( Shader.class );
137 
138         Set<File> set = new LinkedHashSet<>();
139         set.add( new File( getBasedir(), "src/test/jars/test-artifact-1.0-SNAPSHOT.jar" ) );
140 
141         List<Relocator> relocators = new ArrayList<>();
142         relocators.add( new SimpleRelocator( "org.codehaus.plexus.util", "hidden", null, Arrays.asList(
143                 "org.codehaus.plexus.util.xml.Xpp3Dom", "org.codehaus.plexus.util.xml.pull.*") ) );
144 
145         List<ResourceTransformer> resourceTransformers = new ArrayList<>();
146 
147         List<Filter> filters = new ArrayList<>();
148 
149         ShadeRequest shadeRequest = new ShadeRequest();
150         shadeRequest.setJars( set );
151         shadeRequest.setUberJar( jarFile );
152         shadeRequest.setFilters( filters );
153         shadeRequest.setRelocators( relocators );
154         shadeRequest.setResourceTransformers( resourceTransformers );
155 
156         s.shade( shadeRequest );
157 
158         try ( URLClassLoader cl = new URLClassLoader( new URL[]{ jarFile.toURI().toURL() } ) ) {
159             Class<?> c = cl.loadClass( "org.apache.maven.plugins.shade.Lib" );
160     
161             Field field = c.getDeclaredField( "CLASS_REALM_PACKAGE_IMPORT" );
162             assertEquals( "org.codehaus.plexus.util.xml.pull", field.get( null ) );
163     
164             Method method = c.getDeclaredMethod( "getClassRealmPackageImport" );
165             assertEquals( "org.codehaus.plexus.util.xml.pull", method.invoke( null ) );
166         }
167     }
168 
169     /**
170      * Tests if a Filter is installed correctly, also if createSourcesJar is set to true.
171      *
172      * @throws Exception
173      */
174     public void testShadeWithFilter()
175         throws Exception
176     {
177         ShadeMojo mojo = new ShadeMojo();
178 
179         // set createSourcesJar = true
180         Field createSourcesJar = ShadeMojo.class.getDeclaredField( "createSourcesJar" );
181         createSourcesJar.setAccessible( true );
182         createSourcesJar.set( mojo, Boolean.TRUE );
183 
184         // configure artifactResolver (mocked) for mojo
185         ArtifactResolver mockArtifactResolver = new ArtifactResolver()
186         {
187             @Override
188             public ArtifactResult resolveArtifact( ProjectBuildingRequest req, final Artifact art )
189             {
190                 return new ArtifactResult()
191                 {
192 
193                     @Override
194                     public Artifact getArtifact()
195                     {
196                         art.setResolved( true );
197                         String fileName = art.getArtifactId() + "-" + art.getVersion()
198                             + ( art.getClassifier() != null ? "-" + art.getClassifier() : "" ) + ".jar";
199                         art.setFile( new File( fileName ) );
200                         return art;
201                     }
202                 };
203             }
204 
205             @Override
206             public ArtifactResult resolveArtifact( ProjectBuildingRequest req, final ArtifactCoordinate coordinate )
207             {
208                 return new ArtifactResult()
209                 {
210 
211                     @Override
212                     public Artifact getArtifact()
213                     {
214                         Artifact art = mock( Artifact.class );
215                         when( art.getGroupId() ).thenReturn( coordinate.getGroupId() );
216                         when( art.getArtifactId() ).thenReturn( coordinate.getArtifactId() );
217                         when( art.getType() ).thenReturn( coordinate.getExtension() );
218                         when( art.getClassifier() ).thenReturn( coordinate.getClassifier() );
219                         when( art.isResolved() ).thenReturn( true );
220                         String fileName = coordinate.getArtifactId() + "-" + coordinate.getVersion()
221                             + ( coordinate.getClassifier() != null ? "-" + coordinate.getClassifier() : "" ) + ".jar";
222                         when( art.getFile() ).thenReturn( new File( fileName ) );
223                         return art;
224                     }
225                 };
226             }
227         };
228         Field artifactResolverField = ShadeMojo.class.getDeclaredField( "artifactResolver" );
229         artifactResolverField.setAccessible( true );
230         artifactResolverField.set( mojo, mockArtifactResolver );
231 
232         // create and configure MavenProject
233         MavenProject project = new MavenProject();
234         ArtifactHandler artifactHandler = lookup( ArtifactHandler.class );
235         Artifact artifact = new DefaultArtifact( "org.apache.myfaces.core", "myfaces-impl",
236                                                  VersionRange.createFromVersion( "2.0.1-SNAPSHOT" ), "compile", "jar",
237                                                  null, artifactHandler );
238         artifact = mockArtifactResolver.resolveArtifact( null, artifact ).getArtifact(); // setFile and setResolved
239         project.setArtifact( artifact );
240         Field projectField = ShadeMojo.class.getDeclaredField( "project" );
241         projectField.setAccessible( true );
242         projectField.set( mojo, project );
243 
244         // create and configure the ArchiveFilter
245         ArchiveFilter archiveFilter = new ArchiveFilter();
246         Field archiveFilterArtifact = ArchiveFilter.class.getDeclaredField( "artifact" );
247         archiveFilterArtifact.setAccessible( true );
248         archiveFilterArtifact.set( archiveFilter, "org.apache.myfaces.core:myfaces-impl" );
249 
250         // add ArchiveFilter to mojo
251         Field filtersField = ShadeMojo.class.getDeclaredField( "filters" );
252         filtersField.setAccessible( true );
253         filtersField.set( mojo, new ArchiveFilter[]{ archiveFilter } );
254 
255         Field sessionField = ShadeMojo.class.getDeclaredField( "session" );
256         sessionField.setAccessible( true );
257         sessionField.set( mojo, mock( MavenSession.class ) );
258 
259         // invoke getFilters()
260         Method getFilters = ShadeMojo.class.getDeclaredMethod( "getFilters" );
261         getFilters.setAccessible( true );
262         List<Filter> filters = (List<Filter>) getFilters.invoke( mojo);
263 
264         // assertions - there must be one filter
265         assertEquals( 1, filters.size() );
266 
267         // the filter must be able to filter the binary and the sources jar
268         Filter filter = filters.get( 0 );
269         assertTrue( filter.canFilter( new File( "myfaces-impl-2.0.1-SNAPSHOT.jar" ) ) ); // binary jar
270         assertTrue( filter.canFilter( new File( "myfaces-impl-2.0.1-SNAPSHOT-sources.jar" ) ) ); // sources jar
271     }
272 
273     public void shaderWithPattern( String shadedPattern, File jar )
274         throws Exception
275     {
276         Shader s = lookup( Shader.class );
277 
278         Set<File> set = new LinkedHashSet<>();
279 
280         set.add( new File( getBasedir(), "src/test/jars/test-project-1.0-SNAPSHOT.jar" ) );
281 
282         set.add( new File( getBasedir(), "src/test/jars/plexus-utils-1.4.1.jar" ) );
283 
284         List<Relocator> relocators = new ArrayList<>();
285 
286         relocators.add( new SimpleRelocator( "org/codehaus/plexus/util", shadedPattern, null, Arrays.asList(
287                 "org/codehaus/plexus/util/xml/Xpp3Dom", "org/codehaus/plexus/util/xml/pull.*") ) );
288 
289         List<ResourceTransformer> resourceTransformers = new ArrayList<>();
290 
291         resourceTransformers.add( new ComponentsXmlResourceTransformer() );
292 
293         List<Filter> filters = new ArrayList<>();
294 
295         ShadeRequest shadeRequest = new ShadeRequest();
296         shadeRequest.setJars( set );
297         shadeRequest.setUberJar( jar );
298         shadeRequest.setFilters( filters );
299         shadeRequest.setRelocators( relocators );
300         shadeRequest.setResourceTransformers( resourceTransformers );
301 
302         s.shade( shadeRequest );
303     }
304 
305 }