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 @Override
222 public int hashCode() {
223 int hashCode = getUsedDeclaredArtifacts().hashCode();
224 hashCode = (hashCode * 37) + getUsedUndeclaredArtifacts().hashCode();
225 hashCode = (hashCode * 37) + getUnusedDeclaredArtifacts().hashCode();
226 hashCode = (hashCode * 37) + getTestArtifactsWithNonTestScope().hashCode();
227
228 return hashCode;
229 }
230
231
232 @Override
233 public boolean equals(Object object) {
234 if (object instanceof ProjectDependencyAnalysis) {
235 ProjectDependencyAnalysis analysis = (ProjectDependencyAnalysis) object;
236
237 return getUsedDeclaredArtifacts().equals(analysis.getUsedDeclaredArtifacts())
238 && getUsedUndeclaredArtifacts().equals(analysis.getUsedUndeclaredArtifacts())
239 && getUnusedDeclaredArtifacts().equals(analysis.getUnusedDeclaredArtifacts())
240 && getTestArtifactsWithNonTestScope().equals(analysis.getTestArtifactsWithNonTestScope());
241 }
242
243 return false;
244 }
245
246
247
248
249
250
251 @Override
252 public String toString() {
253 StringBuilder buffer = new StringBuilder();
254
255 if (!getUsedDeclaredArtifacts().isEmpty()) {
256 buffer.append("usedDeclaredArtifacts=").append(getUsedDeclaredArtifacts());
257 }
258
259 if (!getUsedUndeclaredArtifacts().isEmpty()) {
260 if (buffer.length() > 0) {
261 buffer.append(",");
262 }
263
264 buffer.append("usedUndeclaredArtifacts=").append(getUsedUndeclaredArtifacts());
265 }
266
267 if (!getUnusedDeclaredArtifacts().isEmpty()) {
268 if (buffer.length() > 0) {
269 buffer.append(",");
270 }
271
272 buffer.append("unusedDeclaredArtifacts=").append(getUnusedDeclaredArtifacts());
273 }
274
275 if (!getTestArtifactsWithNonTestScope().isEmpty()) {
276 if (buffer.length() > 0) {
277 buffer.append(",");
278 }
279
280 buffer.append("testArtifactsWithNonTestScope=").append(getTestArtifactsWithNonTestScope());
281 }
282
283 buffer.insert(0, "[");
284 buffer.insert(0, getClass().getName());
285
286 buffer.append("]");
287
288 return buffer.toString();
289 }
290
291
292
293 private Set<Artifact> safeCopy(Set<Artifact> set) {
294 return (set == null) ? Collections.emptySet() : Collections.unmodifiableSet(new LinkedHashSet<>(set));
295 }
296
297 private static Map<Artifact, Set<String>> safeCopy(Map<Artifact, Set<String>> origMap) {
298 if (origMap == null) {
299 return Collections.emptyMap();
300 }
301
302 Map<Artifact, Set<String>> map = new HashMap<>();
303
304 for (Map.Entry<Artifact, Set<String>> e : origMap.entrySet()) {
305 map.put(e.getKey(), Collections.unmodifiableSet(new LinkedHashSet<>(e.getValue())));
306 }
307
308 return map;
309 }
310
311 private static Map<Artifact, Set<String>> mapWithKeys(Set<Artifact> keys) {
312 if (keys == null) {
313 return Collections.emptyMap();
314 }
315
316 Map<Artifact, Set<String>> map = new HashMap<>();
317
318 for (Artifact k : keys) {
319 map.put(k, Collections.<String>emptySet());
320 }
321
322 return map;
323 }
324 }