1 package org.apache.maven.shared.dependency.analyzer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.LinkedHashSet;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.maven.artifact.Artifact;
32
33
34
35
36
37
38 public class ProjectDependencyAnalysis
39 {
40
41
42 private final Set<Artifact> usedDeclaredArtifacts;
43
44 private final Map<Artifact, Set<String>> usedUndeclaredArtifacts;
45
46 private final Set<Artifact> unusedDeclaredArtifacts;
47
48 private final Set<Artifact> testArtifactsWithNonTestScope;
49
50
51
52
53 public ProjectDependencyAnalysis()
54 {
55 this( null, (Map<Artifact, Set<String>>) null, null, null );
56 }
57
58
59
60
61
62
63
64
65 public ProjectDependencyAnalysis( Set<Artifact> usedDeclaredArtifacts, Set<Artifact> usedUndeclaredArtifacts,
66 Set<Artifact> unusedDeclaredArtifacts )
67 {
68 this( usedDeclaredArtifacts, usedUndeclaredArtifacts,
69 unusedDeclaredArtifacts, Collections.<Artifact>emptySet() );
70 }
71
72
73
74
75
76
77
78
79
80 public ProjectDependencyAnalysis( Set<Artifact> usedDeclaredArtifacts, Set<Artifact> usedUndeclaredArtifacts,
81 Set<Artifact> unusedDeclaredArtifacts,
82 Set<Artifact> testArtifactsWithNonTestScope )
83 {
84 this( usedDeclaredArtifacts,
85 mapWithKeys( usedUndeclaredArtifacts ),
86 unusedDeclaredArtifacts,
87 testArtifactsWithNonTestScope );
88 }
89
90 public ProjectDependencyAnalysis( Set<Artifact> usedDeclaredArtifacts,
91 Map<Artifact, Set<String>> usedUndeclaredArtifacts,
92 Set<Artifact> unusedDeclaredArtifacts,
93 Set<Artifact> testArtifactsWithNonTestScope )
94 {
95 this.usedDeclaredArtifacts = safeCopy( usedDeclaredArtifacts );
96 this.usedUndeclaredArtifacts = safeCopy( usedUndeclaredArtifacts );
97 this.unusedDeclaredArtifacts = safeCopy( unusedDeclaredArtifacts );
98 this.testArtifactsWithNonTestScope = safeCopy( testArtifactsWithNonTestScope );
99 }
100
101
102
103
104
105
106 public Set<Artifact> getUsedDeclaredArtifacts()
107 {
108 return safeCopy( usedDeclaredArtifacts );
109 }
110
111
112
113
114
115
116 public Set<Artifact> getUsedUndeclaredArtifacts()
117 {
118 return safeCopy( usedUndeclaredArtifacts.keySet() );
119 }
120
121
122
123
124
125
126 public Map<Artifact, Set<String>> getUsedUndeclaredArtifactsWithClasses()
127 {
128 return safeCopy( usedUndeclaredArtifacts );
129 }
130
131
132
133
134
135
136 public Set<Artifact> getUnusedDeclaredArtifacts()
137 {
138 return safeCopy( unusedDeclaredArtifacts );
139 }
140
141
142
143
144
145
146 public Set<Artifact> getTestArtifactsWithNonTestScope()
147 {
148 return safeCopy( testArtifactsWithNonTestScope );
149 }
150
151
152
153
154
155
156
157 public ProjectDependencyAnalysis ignoreNonCompile()
158 {
159 Set<Artifact> filteredUnusedDeclared = new HashSet<>( unusedDeclaredArtifacts );
160 filteredUnusedDeclared.removeIf( artifact -> !artifact.getScope().equals( Artifact.SCOPE_COMPILE ) );
161
162 return new ProjectDependencyAnalysis( usedDeclaredArtifacts, usedUndeclaredArtifacts, filteredUnusedDeclared,
163 testArtifactsWithNonTestScope );
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177 @SuppressWarnings( "UnusedReturnValue" )
178 public ProjectDependencyAnalysis forceDeclaredDependenciesUsage( String[] forceUsedDependencies )
179 throws ProjectDependencyAnalyzerException
180 {
181 Set<String> forced = new HashSet<>( Arrays.asList( forceUsedDependencies ) );
182
183 Set<Artifact> forcedUnusedDeclared = new HashSet<>( unusedDeclaredArtifacts );
184 Set<Artifact> forcedUsedDeclared = new HashSet<>( usedDeclaredArtifacts );
185
186 Iterator<Artifact> iter = forcedUnusedDeclared.iterator();
187 while ( iter.hasNext() )
188 {
189 Artifact artifact = iter.next();
190
191 if ( forced.remove( artifact.getGroupId() + ':' + artifact.getArtifactId() ) )
192 {
193
194 iter.remove();
195 forcedUsedDeclared.add( artifact );
196 }
197 }
198
199 if ( !forced.isEmpty() )
200 {
201
202 Set<String> used = new HashSet<>();
203 for ( Artifact artifact : usedDeclaredArtifacts )
204 {
205 String id = artifact.getGroupId() + ':' + artifact.getArtifactId();
206 if ( forced.remove( id ) )
207 {
208 used.add( id );
209 }
210 }
211
212 StringBuilder builder = new StringBuilder();
213 if ( !forced.isEmpty() )
214 {
215 builder.append( "not declared: " ).append( forced );
216 }
217 if ( !used.isEmpty() )
218 {
219 if ( builder.length() > 0 )
220 {
221 builder.append( " and " );
222 }
223 builder.append( "declared but already detected as used: " ).append( used );
224 }
225 throw new ProjectDependencyAnalyzerException( "Trying to force use of dependencies which are " + builder );
226 }
227
228 return new ProjectDependencyAnalysis( forcedUsedDeclared, usedUndeclaredArtifacts, forcedUnusedDeclared,
229 testArtifactsWithNonTestScope );
230 }
231
232
233
234
235
236
237 public int hashCode()
238 {
239 int hashCode = getUsedDeclaredArtifacts().hashCode();
240 hashCode = ( hashCode * 37 ) + getUsedUndeclaredArtifacts().hashCode();
241 hashCode = ( hashCode * 37 ) + getUnusedDeclaredArtifacts().hashCode();
242 hashCode = ( hashCode * 37 ) + getTestArtifactsWithNonTestScope().hashCode();
243
244 return hashCode;
245 }
246
247
248 public boolean equals( Object object )
249 {
250 if ( object instanceof ProjectDependencyAnalysis )
251 {
252 ProjectDependencyAnalysis analysis = (ProjectDependencyAnalysis) object;
253
254 return getUsedDeclaredArtifacts().equals( analysis.getUsedDeclaredArtifacts() )
255 && getUsedUndeclaredArtifacts().equals( analysis.getUsedUndeclaredArtifacts() )
256 && getUnusedDeclaredArtifacts().equals( analysis.getUnusedDeclaredArtifacts() )
257 && getTestArtifactsWithNonTestScope().equals( analysis.getTestArtifactsWithNonTestScope() );
258 }
259
260 return false;
261 }
262
263
264
265
266
267
268 public String toString()
269 {
270 StringBuilder buffer = new StringBuilder();
271
272 if ( !getUsedDeclaredArtifacts().isEmpty() )
273 {
274 buffer.append( "usedDeclaredArtifacts=" ).append( getUsedDeclaredArtifacts() );
275 }
276
277 if ( !getUsedUndeclaredArtifacts().isEmpty() )
278 {
279 if ( buffer.length() > 0 )
280 {
281 buffer.append( "," );
282 }
283
284 buffer.append( "usedUndeclaredArtifacts=" ).append( getUsedUndeclaredArtifacts() );
285 }
286
287 if ( !getUnusedDeclaredArtifacts().isEmpty() )
288 {
289 if ( buffer.length() > 0 )
290 {
291 buffer.append( "," );
292 }
293
294 buffer.append( "unusedDeclaredArtifacts=" ).append( getUnusedDeclaredArtifacts() );
295 }
296
297 if ( !getTestArtifactsWithNonTestScope().isEmpty() )
298 {
299 if ( buffer.length() > 0 )
300 {
301 buffer.append( "," );
302 }
303
304 buffer.append( "testArtifactsWithNonTestScope=" ).append( getTestArtifactsWithNonTestScope() );
305 }
306
307 buffer.insert( 0, "[" );
308 buffer.insert( 0, getClass().getName() );
309
310 buffer.append( "]" );
311
312 return buffer.toString();
313 }
314
315
316
317 private Set<Artifact> safeCopy( Set<Artifact> set )
318 {
319 return ( set == null ) ? Collections.emptySet() : Collections.unmodifiableSet( new LinkedHashSet<>( set ) );
320 }
321
322 private static Map<Artifact, Set<String>> safeCopy( Map<Artifact, Set<String>> origMap )
323 {
324 if ( origMap == null )
325 {
326 return Collections.emptyMap();
327 }
328
329 Map<Artifact, Set<String>> map = new HashMap<>();
330
331 for ( Map.Entry<Artifact, Set<String>> e : origMap.entrySet() )
332 {
333 map.put( e.getKey(), Collections.unmodifiableSet( new LinkedHashSet<>( e.getValue() ) ) );
334 }
335
336 return map;
337 }
338
339 private static Map<Artifact, Set<String>> mapWithKeys( Set<Artifact> keys )
340 {
341 if ( keys == null )
342 {
343 return Collections.emptyMap();
344 }
345
346 Map<Artifact, Set<String>> map = new HashMap<>();
347
348 for ( Artifact k : keys )
349 {
350 map.put( k, Collections.<String>emptySet() );
351 }
352
353 return map;
354 }
355 }