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