1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.impl;
20
21 import java.io.IOException;
22 import java.lang.module.ModuleDescriptor;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Optional;
31 import java.util.Set;
32 import java.util.function.Predicate;
33
34 import org.apache.maven.api.Dependency;
35 import org.apache.maven.api.JavaPathType;
36 import org.apache.maven.api.Node;
37 import org.apache.maven.api.PathType;
38 import org.apache.maven.api.services.DependencyResolverException;
39 import org.apache.maven.api.services.DependencyResolverRequest;
40 import org.apache.maven.api.services.DependencyResolverResult;
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class DefaultDependencyResolverResult implements DependencyResolverResult {
55
56
57
58 private final DependencyResolverRequest request;
59
60
61
62 private final List<Exception> exceptions;
63
64
65
66
67 private final Node root;
68
69
70
71
72 private final List<Node> nodes;
73
74
75
76
77 private final List<Path> paths;
78
79
80
81
82 private final Map<PathType, List<Path>> dispatchedPaths;
83
84
85
86
87 private final Map<Dependency, Path> dependencies;
88
89
90
91
92
93 private PathModularization outputModules;
94
95
96
97
98 private final PathModularizationCache cache;
99
100
101
102
103
104
105
106
107
108
109
110 public DefaultDependencyResolverResult(
111 DependencyResolverRequest request,
112 PathModularizationCache cache,
113 List<Exception> exceptions,
114 Node root,
115 int count) {
116 this.request = request;
117 this.cache = cache;
118 this.exceptions = exceptions;
119 this.root = root;
120 nodes = new ArrayList<>(count);
121 paths = new ArrayList<>(count);
122 dispatchedPaths = new LinkedHashMap<>();
123 dependencies = new LinkedHashMap<>(count + count / 3);
124 }
125
126
127
128
129
130
131
132 private void addPathElement(PathType type, Path path) {
133 dispatchedPaths.computeIfAbsent(type, (t) -> new ArrayList<>()).add(path);
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 void addOutputDirectory(Path main, Path test) throws IOException {
172 if (outputModules != null) {
173 throw new IllegalStateException("Output directories must be set first and only once.");
174 }
175 if (main != null) {
176 outputModules = cache.getModuleInfo(main);
177 addPathElement(outputModules.getPathType(), main);
178 } else {
179 outputModules = PathModularization.NONE;
180 }
181 if (test != null) {
182 boolean addToClasspath = true;
183 PathModularization testModules = cache.getModuleInfo(test);
184 boolean isModuleHierarchy = outputModules.isModuleHierarchy || testModules.isModuleHierarchy;
185 for (Object value : outputModules.descriptors.values()) {
186 String moduleName = name(value);
187 Path subdir = test;
188 if (isModuleHierarchy) {
189
190 Path path = test.resolve(moduleName);
191 if (!Files.isDirectory(path)) {
192
193 continue;
194 }
195 subdir = path;
196 }
197
198 addPathElement(JavaPathType.patchModule(moduleName), subdir);
199 addToClasspath = false;
200 }
201
202
203
204
205 for (Map.Entry<Path, Object> entry : testModules.descriptors.entrySet()) {
206 if (!outputModules.containsModule(name(entry.getValue()))) {
207 addPathElement(JavaPathType.MODULES, entry.getKey());
208 addToClasspath = false;
209 }
210 }
211 if (addToClasspath) {
212 addPathElement(JavaPathType.CLASSES, test);
213 }
214 }
215 }
216
217
218
219
220
221
222 void addNode(Node node) {
223 nodes.add(node);
224 }
225
226
227
228
229
230
231
232
233
234
235
236 void addDependency(Node node, Dependency dep, Predicate<PathType> filter, Path path) throws IOException {
237 nodes.add(node);
238 if (dep == null) {
239 return;
240 }
241 if (dependencies.put(dep, path) != null) {
242 throw new IllegalStateException("Duplicated key: " + dep);
243 }
244 if (path == null) {
245 return;
246 }
247 paths.add(path);
248
249
250
251
252
253
254
255 Set<PathType> pathTypes = dep.getType().getPathTypes();
256 if (containsPatches(pathTypes)) {
257 if (outputModules == null) {
258
259 outputModules = PathModularization.NONE;
260 }
261 PathType type = null;
262 for (Map.Entry<Path, Object> info :
263 cache.getModuleInfo(path).descriptors.entrySet()) {
264 String moduleName = name(info.getValue());
265 type = JavaPathType.patchModule(moduleName);
266 if (!containsModule(moduleName)) {
267
268
269
270
271
272 type = cache.selectPathType(pathTypes, filter, path).orElse(type);
273 }
274 addPathElement(type, info.getKey());
275
276 }
277
278
279
280
281
282 if (type == null) {
283 Path main = findArtifactPath(dep.getGroupId(), dep.getArtifactId());
284 if (main != null) {
285 for (Map.Entry<Path, Object> info :
286 cache.getModuleInfo(main).descriptors.entrySet()) {
287 type = JavaPathType.patchModule(name(info.getValue()));
288 addPathElement(type, info.getKey());
289
290 }
291 }
292 }
293 if (type != null) {
294 return;
295 }
296 }
297 addPathElement(cache.selectPathType(pathTypes, filter, path).orElse(PathType.UNRESOLVED), path);
298 }
299
300
301
302
303 private boolean containsPatches(Set<PathType> types) {
304 for (PathType type : types) {
305 if (type instanceof JavaPathType.Modular modular) {
306 type = modular.rawType();
307 }
308 if (JavaPathType.PATCH_MODULE.equals(type)) {
309 return true;
310 }
311 }
312 return false;
313 }
314
315
316
317
318
319
320 private boolean containsModule(String moduleName) throws IOException {
321 for (Path path : dispatchedPaths.getOrDefault(JavaPathType.MODULES, Collections.emptyList())) {
322 if (cache.getModuleInfo(path).containsModule(moduleName)) {
323 return true;
324 }
325 }
326 return false;
327 }
328
329
330
331
332
333
334
335
336 private Path findArtifactPath(String group, String artifact) throws IOException {
337 for (Map.Entry<Dependency, Path> entry : dependencies.entrySet()) {
338 Dependency dep = entry.getKey();
339 if (group.equals(dep.getGroupId()) && artifact.equals(dep.getArtifactId())) {
340 return entry.getValue();
341 }
342 }
343 return null;
344 }
345
346 @Override
347 public DependencyResolverRequest getRequest() {
348 return request;
349 }
350
351 @Override
352 public List<Exception> getExceptions() {
353 return exceptions;
354 }
355
356 @Override
357 public Node getRoot() {
358 return root;
359 }
360
361 @Override
362 public List<Node> getNodes() {
363 return nodes;
364 }
365
366 @Override
367 public List<Path> getPaths() {
368 return paths;
369 }
370
371 @Override
372 public Map<PathType, List<Path>> getDispatchedPaths() {
373 return dispatchedPaths;
374 }
375
376 @Override
377 public Map<Dependency, Path> getDependencies() {
378 return dependencies;
379 }
380
381 @Override
382 public Optional<ModuleDescriptor> getModuleDescriptor(Path dependency) throws IOException {
383 Object value = cache.getModuleInfo(dependency).descriptors.get(dependency);
384 return (value instanceof ModuleDescriptor moduleDescriptor) ? Optional.of(moduleDescriptor) : Optional.empty();
385 }
386
387 @Override
388 public Optional<String> getModuleName(Path dependency) throws IOException {
389 return Optional.ofNullable(
390 name(cache.getModuleInfo(dependency).descriptors.get(dependency)));
391 }
392
393
394
395
396 private static String name(final Object value) {
397 if (value instanceof String string) {
398 return string;
399 } else if (value instanceof ModuleDescriptor moduleDescriptor) {
400 return moduleDescriptor.name();
401 } else {
402 return null;
403 }
404 }
405
406 @Override
407 public Optional<String> warningForFilenameBasedAutomodules() {
408 try {
409 return cache.warningForFilenameBasedAutomodules(dispatchedPaths.get(JavaPathType.MODULES));
410 } catch (IOException e) {
411 throw new DependencyResolverException("Cannot read module information.", e);
412 }
413 }
414 }