1 package org.apache.maven.plugins.shade.mojo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.factory.ArtifactFactory;
24 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
25 import org.apache.maven.artifact.repository.ArtifactRepository;
26 import org.apache.maven.artifact.resolver.ArtifactCollector;
27 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
28 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
29 import org.apache.maven.artifact.resolver.ArtifactResolver;
30 import org.apache.maven.execution.MavenSession;
31 import org.apache.maven.model.Dependency;
32 import org.apache.maven.model.Exclusion;
33 import org.apache.maven.model.Model;
34 import org.apache.maven.plugin.AbstractMojo;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugins.annotations.Component;
37 import org.apache.maven.plugins.annotations.LifecyclePhase;
38 import org.apache.maven.plugins.annotations.Mojo;
39 import org.apache.maven.plugins.annotations.Parameter;
40 import org.apache.maven.plugins.annotations.ResolutionScope;
41 import org.apache.maven.plugins.shade.ShadeRequest;
42 import org.apache.maven.plugins.shade.Shader;
43 import org.apache.maven.plugins.shade.filter.Filter;
44 import org.apache.maven.plugins.shade.filter.MinijarFilter;
45 import org.apache.maven.plugins.shade.filter.SimpleFilter;
46 import org.apache.maven.plugins.shade.pom.PomWriter;
47 import org.apache.maven.plugins.shade.relocation.Relocator;
48 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
49 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
50 import org.apache.maven.project.DefaultProjectBuildingRequest;
51 import org.apache.maven.project.MavenProject;
52 import org.apache.maven.project.MavenProjectHelper;
53 import org.apache.maven.project.ProjectBuilder;
54 import org.apache.maven.project.ProjectBuildingException;
55 import org.apache.maven.project.ProjectBuildingRequest;
56 import org.apache.maven.project.ProjectBuildingResult;
57 import org.apache.maven.shared.dependency.graph.DependencyNode;
58 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
59 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
60 import org.codehaus.plexus.PlexusConstants;
61 import org.codehaus.plexus.PlexusContainer;
62 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
63 import org.codehaus.plexus.context.Context;
64 import org.codehaus.plexus.context.ContextException;
65 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
66 import org.codehaus.plexus.util.IOUtil;
67 import org.codehaus.plexus.util.WriterFactory;
68
69 import java.io.File;
70 import java.io.FileInputStream;
71 import java.io.FileOutputStream;
72 import java.io.IOException;
73 import java.io.Writer;
74 import java.util.ArrayList;
75 import java.util.Arrays;
76 import java.util.Collections;
77 import java.util.HashMap;
78 import java.util.HashSet;
79 import java.util.LinkedHashSet;
80 import java.util.List;
81 import java.util.Map;
82 import java.util.Set;
83
84
85
86
87
88
89
90
91
92 @Mojo( name = "shade", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true,
93 requiresDependencyResolution = ResolutionScope.RUNTIME )
94 public class ShadeMojo
95 extends AbstractMojo
96 implements Contextualizable
97 {
98
99
100
101 @Component
102 private MavenSession session;
103
104
105
106
107 @Component
108 private MavenProject project;
109
110 @Component
111 private MavenProjectHelper projectHelper;
112
113 @Component( hint = "default", role = org.apache.maven.plugins.shade.Shader.class )
114 private Shader shader;
115
116
117
118
119 @Component
120 private DependencyGraphBuilder dependencyGraphBuilder;
121
122
123
124
125 @Component
126 private ProjectBuilder projectBuilder;
127
128
129
130
131 @Component
132 private ArtifactMetadataSource artifactMetadataSource;
133
134
135
136
137 @Parameter( readonly = true, required = true, defaultValue = "${project.remoteArtifactRepositories}" )
138 protected List<ArtifactRepository> remoteArtifactRepositories;
139
140
141
142
143 @Parameter( readonly = true, required = true, defaultValue = "${localRepository}" )
144 protected ArtifactRepository localRepository;
145
146
147
148
149 @Component
150 protected ArtifactFactory artifactFactory;
151
152
153
154
155 @Component
156 protected ArtifactResolver artifactResolver;
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 @Parameter
177 private ArtifactSet artifactSet;
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 @Parameter
198 private PackageRelocation[] relocations;
199
200
201
202
203
204 @Parameter
205 private ResourceTransformer[] transformers;
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228 @Parameter
229 private ArchiveFilter[] filters;
230
231
232
233
234 @Parameter( defaultValue = "${project.build.directory}" )
235 private File outputDirectory;
236
237
238
239
240
241
242
243
244 @Parameter
245 private String finalName;
246
247
248
249
250
251
252
253 @Parameter( defaultValue = "${project.artifactId}" )
254 private String shadedArtifactId;
255
256
257
258
259
260 @Parameter
261 private String shadedGroupFilter;
262
263
264
265
266
267
268 @Parameter
269 private boolean shadedArtifactAttached;
270
271
272
273
274
275
276
277
278 @Parameter( defaultValue = "true" )
279 private boolean createDependencyReducedPom;
280
281
282
283
284
285
286
287
288
289
290 @Parameter( defaultValue = "${basedir}/dependency-reduced-pom.xml" )
291 private File dependencyReducedPomLocation;
292
293
294
295
296
297
298
299
300 @Parameter( defaultValue = "false" )
301 private boolean generateUniqueDependencyReducedPom;
302
303
304
305
306
307 @Parameter
308 private boolean keepDependenciesWithProvidedScope;
309
310
311
312
313
314
315 @Parameter
316 private boolean promoteTransitiveDependencies;
317
318
319
320
321 @Parameter( defaultValue = "shaded" )
322 private String shadedClassifierName;
323
324
325
326
327 @Parameter
328 private boolean createSourcesJar;
329
330
331
332
333
334
335
336 @Parameter(property = "shadeSourcesContent", defaultValue = "false")
337 private boolean shadeSourcesContent;
338
339
340
341
342
343
344
345 @Parameter
346 private boolean minimizeJar;
347
348
349
350
351
352
353
354
355
356 @Parameter
357 private File outputFile;
358
359
360
361
362
363
364 @Parameter
365 private String shaderHint;
366
367
368
369
370 private PlexusContainer plexusContainer;
371
372 public void contextualize( Context context )
373 throws ContextException
374 {
375 plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
376 }
377
378
379
380
381 public void execute()
382 throws MojoExecutionException
383 {
384
385 if ( shaderHint != null )
386 {
387 try
388 {
389 shader = (Shader) plexusContainer.lookup( Shader.ROLE, shaderHint );
390 }
391 catch ( ComponentLookupException e )
392 {
393 throw new MojoExecutionException(
394 "unable to lookup own Shader implementation with hint:'" + shaderHint + "'", e );
395 }
396 }
397
398 Set<File> artifacts = new LinkedHashSet<File>();
399 Set<String> artifactIds = new LinkedHashSet<String>();
400 Set<File> sourceArtifacts = new LinkedHashSet<File>();
401
402 ArtifactSelector artifactSelector =
403 new ArtifactSelector( project.getArtifact(), artifactSet, shadedGroupFilter );
404
405 if ( artifactSelector.isSelected( project.getArtifact() ) && !"pom".equals( project.getArtifact().getType() ) )
406 {
407 if ( invalidMainArtifact() )
408 {
409 getLog().error( "The project main artifact does not exist. This could have the following" );
410 getLog().error( "reasons:" );
411 getLog().error( "- You have invoked the goal directly from the command line. This is not" );
412 getLog().error( " supported. Please add the goal to the default lifecycle via an" );
413 getLog().error( " <execution> element in your POM and use \"mvn package\" to have it run." );
414 getLog().error( "- You have bound the goal to a lifecycle phase before \"package\". Please" );
415 getLog().error( " remove this binding from your POM such that the goal will be run in" );
416 getLog().error( " the proper phase." );
417 getLog().error(
418 "- You removed the configuration of the maven-jar-plugin that produces the main artifact." );
419 throw new MojoExecutionException(
420 "Failed to create shaded artifact, " + "project main artifact does not exist." );
421 }
422
423 artifacts.add( project.getArtifact().getFile() );
424
425 if ( createSourcesJar )
426 {
427 File file = shadedSourcesArtifactFile();
428 if ( file.isFile() )
429 {
430 sourceArtifacts.add( file );
431 }
432 }
433 }
434
435 for ( Artifact artifact : project.getArtifacts() )
436 {
437 if ( !artifactSelector.isSelected( artifact ) )
438 {
439 getLog().info( "Excluding " + artifact.getId() + " from the shaded jar." );
440
441 continue;
442 }
443
444 if ( "pom".equals( artifact.getType() ) )
445 {
446 getLog().info( "Skipping pom dependency " + artifact.getId() + " in the shaded jar." );
447 continue;
448 }
449
450 getLog().info( "Including " + artifact.getId() + " in the shaded jar." );
451
452 artifacts.add( artifact.getFile() );
453 artifactIds.add( getId( artifact ) );
454
455 if ( createSourcesJar )
456 {
457 File file = resolveArtifactSources( artifact );
458 if ( file != null )
459 {
460 sourceArtifacts.add( file );
461 }
462 }
463 }
464
465 File outputJar = ( outputFile != null ) ? outputFile : shadedArtifactFileWithClassifier();
466 File sourcesJar = shadedSourceArtifactFileWithClassifier();
467
468
469 try
470 {
471 List<Filter> filters = getFilters();
472
473 List<Relocator> relocators = getRelocators();
474
475 List<ResourceTransformer> resourceTransformers = getResourceTransformers();
476
477 ShadeRequest shadeRequest = new ShadeRequest();
478 shadeRequest.setJars( artifacts );
479 shadeRequest.setUberJar( outputJar );
480 shadeRequest.setFilters( filters );
481 shadeRequest.setRelocators( relocators );
482 shadeRequest.setResourceTransformers( resourceTransformers );
483
484 shader.shade( shadeRequest );
485
486 if ( createSourcesJar )
487 {
488 ShadeRequest shadeSourcesRequest = new ShadeRequest();
489 shadeSourcesRequest.setJars( sourceArtifacts );
490 shadeSourcesRequest.setUberJar( sourcesJar );
491 shadeSourcesRequest.setFilters( filters );
492 shadeSourcesRequest.setRelocators( relocators );
493 shadeSourcesRequest.setResourceTransformers( resourceTransformers );
494 shadeSourcesRequest.setShadeSourcesContent( shadeSourcesContent );
495
496 shader.shade( shadeSourcesRequest );
497 }
498
499 if ( outputFile == null )
500 {
501 boolean renamed = false;
502
503
504
505
506 if ( finalName != null && finalName.length() > 0 && !finalName.equals(
507 project.getBuild().getFinalName() ) )
508 {
509 String finalFileName = finalName + "." + project.getArtifact().getArtifactHandler().getExtension();
510 File finalFile = new File( outputDirectory, finalFileName );
511 replaceFile( finalFile, outputJar );
512 outputJar = finalFile;
513
514 renamed = true;
515 }
516
517 if ( shadedArtifactAttached )
518 {
519 getLog().info( "Attaching shaded artifact." );
520 projectHelper.attachArtifact( project, project.getArtifact().getType(), shadedClassifierName,
521 outputJar );
522 if ( createSourcesJar )
523 {
524 projectHelper.attachArtifact( project, "jar", shadedClassifierName + "-sources", sourcesJar );
525 }
526 }
527 else if ( !renamed )
528 {
529 getLog().info( "Replacing original artifact with shaded artifact." );
530 File originalArtifact = project.getArtifact().getFile();
531 replaceFile( originalArtifact, outputJar );
532
533 if ( createSourcesJar )
534 {
535 File shadedSources = shadedSourcesArtifactFile();
536
537 replaceFile( shadedSources, sourcesJar );
538
539 projectHelper.attachArtifact( project, "jar", "sources", shadedSources );
540 }
541
542 if ( createDependencyReducedPom )
543 {
544 createDependencyReducedPom( artifactIds );
545 }
546 }
547 }
548 }
549 catch ( Exception e )
550 {
551 throw new MojoExecutionException( "Error creating shaded jar: " + e.getMessage(), e );
552 }
553 }
554
555 private boolean invalidMainArtifact()
556 {
557 return project.getArtifact().getFile() == null || !project.getArtifact().getFile().isFile();
558 }
559
560 private void replaceFile( File oldFile, File newFile )
561 throws MojoExecutionException
562 {
563 getLog().info( "Replacing " + oldFile + " with " + newFile );
564
565 File origFile = new File( outputDirectory, "original-" + oldFile.getName() );
566 if ( oldFile.exists() && !oldFile.renameTo( origFile ) )
567 {
568
569 System.gc();
570 System.gc();
571
572 if ( !oldFile.renameTo( origFile ) )
573 {
574
575 try
576 {
577 FileOutputStream fout = new FileOutputStream( origFile );
578 FileInputStream fin = new FileInputStream( oldFile );
579 try
580 {
581 IOUtil.copy( fin, fout );
582 }
583 finally
584 {
585 IOUtil.close( fin );
586 IOUtil.close( fout );
587 }
588 }
589 catch ( IOException ex )
590 {
591
592 getLog().warn( ex );
593 }
594 }
595 }
596 if ( !newFile.renameTo( oldFile ) )
597 {
598
599 System.gc();
600 System.gc();
601
602 if ( !newFile.renameTo( oldFile ) )
603 {
604
605 try
606 {
607 FileOutputStream fout = new FileOutputStream( oldFile );
608 FileInputStream fin = new FileInputStream( newFile );
609 try
610 {
611 IOUtil.copy( fin, fout );
612 }
613 finally
614 {
615 IOUtil.close( fin );
616 IOUtil.close( fout );
617 }
618 }
619 catch ( IOException ex )
620 {
621 throw new MojoExecutionException( "Could not replace original artifact with shaded artifact!", ex );
622 }
623 }
624 }
625 }
626
627 private File resolveArtifactSources( Artifact artifact )
628 {
629
630 Artifact resolvedArtifact =
631 artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
632 artifact.getVersion(), "java-source", "sources" );
633
634 try
635 {
636 artifactResolver.resolve( resolvedArtifact, remoteArtifactRepositories, localRepository );
637 }
638 catch ( ArtifactNotFoundException e )
639 {
640
641 }
642 catch ( ArtifactResolutionException e )
643 {
644 getLog().warn( "Could not get sources for " + artifact );
645 }
646
647 if ( resolvedArtifact.isResolved() )
648 {
649 return resolvedArtifact.getFile();
650 }
651 return null;
652 }
653
654 private List<Relocator> getRelocators()
655 {
656 List<Relocator> relocators = new ArrayList<Relocator>();
657
658 if ( relocations == null )
659 {
660 return relocators;
661 }
662
663 for ( int i = 0; i < relocations.length; i++ )
664 {
665 PackageRelocation r = relocations[i];
666
667 relocators.add( new SimpleRelocator( r.getPattern(), r.getShadedPattern(), r.getIncludes(), r.getExcludes(),
668 r.isRawString() ) );
669 }
670
671 return relocators;
672 }
673
674 private List<ResourceTransformer> getResourceTransformers()
675 {
676 if ( transformers == null )
677 {
678 return Collections.emptyList();
679 }
680
681 return Arrays.asList( transformers );
682 }
683
684 private List<Filter> getFilters()
685 throws MojoExecutionException
686 {
687 List<Filter> filters = new ArrayList<Filter>();
688 List<SimpleFilter> simpleFilters = new ArrayList<SimpleFilter>();
689
690 if ( this.filters != null && this.filters.length > 0 )
691 {
692 Map<Artifact, ArtifactId> artifacts = new HashMap<Artifact, ArtifactId>();
693
694 artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) );
695
696 for ( Artifact artifact : project.getArtifacts() )
697 {
698 artifacts.put( artifact, new ArtifactId( artifact ) );
699 }
700
701 for ( ArchiveFilter filter : this.filters )
702 {
703 ArtifactId pattern = new ArtifactId( filter.getArtifact() );
704
705 Set<File> jars = new HashSet<File>();
706
707 for ( Map.Entry<Artifact, ArtifactId> entry : artifacts.entrySet() )
708 {
709 if ( entry.getValue().matches( pattern ) )
710 {
711 Artifact artifact = entry.getKey();
712
713 jars.add( artifact.getFile() );
714
715 if ( createSourcesJar )
716 {
717 File file = resolveArtifactSources( artifact );
718 if ( file != null )
719 {
720 jars.add( file );
721 }
722 }
723 }
724 }
725
726 if ( jars.isEmpty() )
727 {
728 getLog().info( "No artifact matching filter " + filter.getArtifact() );
729
730 continue;
731 }
732
733 simpleFilters.add( new SimpleFilter( jars, filter.getIncludes(), filter.getExcludes() ) );
734 }
735 }
736
737 filters.addAll( simpleFilters );
738
739 if ( minimizeJar )
740 {
741 getLog().info( "Minimizing jar " + project.getArtifact() );
742
743 try
744 {
745 filters.add( new MinijarFilter( project, getLog(), simpleFilters ) );
746 }
747 catch ( IOException e )
748 {
749 throw new MojoExecutionException( "Failed to analyze class dependencies", e );
750 }
751 }
752
753 return filters;
754 }
755
756 private File shadedArtifactFileWithClassifier()
757 {
758 Artifact artifact = project.getArtifact();
759 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "."
760 + artifact.getArtifactHandler().getExtension();
761 return new File( outputDirectory, shadedName );
762 }
763
764 private File shadedSourceArtifactFileWithClassifier()
765 {
766 Artifact artifact = project.getArtifact();
767 final String shadedName =
768 shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "-sources."
769 + artifact.getArtifactHandler().getExtension();
770 return new File( outputDirectory, shadedName );
771 }
772
773 private File shadedSourcesArtifactFile()
774 {
775 Artifact artifact = project.getArtifact();
776
777 String shadedName;
778
779 if ( project.getBuild().getFinalName() != null )
780 {
781 shadedName = project.getBuild().getFinalName() + "-sources." + artifact.getArtifactHandler().getExtension();
782 }
783 else
784 {
785 shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-sources."
786 + artifact.getArtifactHandler().getExtension();
787 }
788
789 return new File( outputDirectory, shadedName );
790 }
791
792
793
794 private void createDependencyReducedPom( Set<String> artifactsToRemove )
795 throws IOException, DependencyGraphBuilderException, ProjectBuildingException
796 {
797 Model model = project.getOriginalModel();
798 List<Dependency> dependencies = new ArrayList<Dependency>();
799
800 boolean modified = false;
801
802 List<Dependency> transitiveDeps = new ArrayList<Dependency>();
803
804 for ( Artifact artifact : project.getArtifacts() )
805 {
806 if ( "pom".equals( artifact.getType() ) )
807 {
808
809 continue;
810 }
811
812
813 Dependency dep = new Dependency();
814 dep.setArtifactId( artifact.getArtifactId() );
815 if ( artifact.hasClassifier() )
816 {
817 dep.setClassifier( artifact.getClassifier() );
818 }
819 dep.setGroupId( artifact.getGroupId() );
820 dep.setOptional( artifact.isOptional() );
821 dep.setScope( artifact.getScope() );
822 dep.setType( artifact.getType() );
823 dep.setVersion( artifact.getVersion() );
824
825
826
827 transitiveDeps.add( dep );
828 }
829 List<Dependency> origDeps = project.getDependencies();
830
831 if ( promoteTransitiveDependencies )
832 {
833 origDeps = transitiveDeps;
834 }
835
836 for ( Dependency d : origDeps )
837 {
838 dependencies.add( d );
839
840 String id = getId( d );
841
842 if ( artifactsToRemove.contains( id ) )
843 {
844 modified = true;
845
846 if ( keepDependenciesWithProvidedScope )
847 {
848 d.setScope( "provided" );
849 }
850 else
851 {
852 dependencies.remove( d );
853 }
854 }
855 }
856
857
858 if ( modified )
859 {
860 while ( modified )
861 {
862
863 model.setDependencies( dependencies );
864
865 if ( generateUniqueDependencyReducedPom )
866 {
867 dependencyReducedPomLocation = File.createTempFile( "dependency-reduced-pom-", ".xml", project.getBasedir() );
868 project.getProperties().setProperty( "maven.shade.dependency-reduced-pom", dependencyReducedPomLocation.getAbsolutePath() );
869 }
870 else
871 {
872 if ( dependencyReducedPomLocation == null )
873 {
874
875 dependencyReducedPomLocation = new File( project.getBasedir(), "dependency-reduced-pom.xml" );
876 }
877 }
878
879 File f = dependencyReducedPomLocation;
880 getLog().info( "Dependency-reduced POM written at: " + f.getAbsolutePath() );
881
882 if ( f.exists() )
883 {
884 f.delete();
885 }
886
887 Writer w = WriterFactory.newXmlWriter( f );
888
889 String origRelativePath = null;
890 String replaceRelativePath = null;
891 if ( model.getParent() != null )
892 {
893 origRelativePath = model.getParent().getRelativePath();
894
895 }
896 replaceRelativePath = origRelativePath;
897
898 if ( origRelativePath == null )
899 {
900 origRelativePath = "../pom.xml";
901 }
902
903 if ( model.getParent() != null )
904 {
905 File parentFile =
906 new File( project.getBasedir(), model.getParent().getRelativePath() ).getCanonicalFile();
907 if ( !parentFile.isFile() )
908 {
909 parentFile = new File( parentFile, "pom.xml" );
910 }
911
912 parentFile = parentFile.getCanonicalFile();
913
914 String relPath = RelativizePath.convertToRelativePath( parentFile, f );
915 model.getParent().setRelativePath( relPath );
916 }
917
918 try
919 {
920 PomWriter.write( w, model, true );
921 }
922 finally
923 {
924 if ( model.getParent() != null )
925 {
926 model.getParent().setRelativePath( replaceRelativePath );
927 }
928 w.close();
929 }
930
931 ProjectBuildingRequest projectBuildingRequest =
932 new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
933 projectBuildingRequest.setLocalRepository( localRepository );
934 projectBuildingRequest.setRemoteRepositories( remoteArtifactRepositories );
935
936 ProjectBuildingResult result = projectBuilder.build( f, projectBuildingRequest );
937
938 modified = updateExcludesInDeps( result.getProject(), dependencies, transitiveDeps );
939 }
940
941 project.setFile( dependencyReducedPomLocation );
942 }
943 }
944
945 private String getId( Artifact artifact )
946 {
947 return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getType(), artifact.getClassifier() );
948 }
949
950 private String getId( Dependency dependency )
951 {
952 return getId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(),
953 dependency.getClassifier() );
954 }
955
956 private String getId( String groupId, String artifactId, String type, String classifier )
957 {
958 return groupId + ":" + artifactId + ":" + type + ":" + ( ( classifier != null ) ? classifier : "" );
959 }
960
961 public boolean updateExcludesInDeps( MavenProject project, List<Dependency> dependencies,
962 List<Dependency> transitiveDeps )
963 throws DependencyGraphBuilderException
964 {
965 DependencyNode node = dependencyGraphBuilder.buildDependencyGraph( project, null );
966 boolean modified = false;
967 for ( DependencyNode n2 : node.getChildren() )
968 {
969 for ( DependencyNode n3 : n2.getChildren() )
970 {
971
972
973
974
975
976
977 boolean found = false;
978 for ( Dependency dep : transitiveDeps )
979 {
980 if ( dep.getArtifactId().equals( n3.getArtifact().getArtifactId() )
981 && dep.getGroupId().equals( n3.getArtifact().getGroupId() ) )
982 {
983 found = true;
984 break;
985 }
986 }
987
988 if ( !found )
989 {
990 for ( Dependency dep : dependencies )
991 {
992 if ( dep.getArtifactId().equals( n2.getArtifact().getArtifactId() )
993 && dep.getGroupId().equals( n2.getArtifact().getGroupId() ) )
994 {
995 Exclusion exclusion = new Exclusion();
996 exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
997 exclusion.setGroupId( n3.getArtifact().getGroupId() );
998 dep.addExclusion( exclusion );
999 modified = true;
1000 break;
1001 }
1002 }
1003 }
1004 }
1005 }
1006 return modified;
1007 }
1008 }