1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.dependency.analyze;
20
21 import java.io.IOException;
22 import java.io.Reader;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.stream.Collectors;
30
31 import org.apache.maven.model.Dependency;
32 import org.apache.maven.model.Model;
33 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
34 import org.apache.maven.plugin.AbstractMojo;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.MojoFailureException;
37 import org.apache.maven.plugins.annotations.Mojo;
38 import org.apache.maven.plugins.annotations.Parameter;
39 import org.apache.maven.project.MavenProject;
40 import org.codehaus.plexus.util.ReaderFactory;
41 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
42
43
44
45
46
47
48
49 @Mojo(name = "analyze-duplicate", aggregator = false, threadSafe = true)
50 public class AnalyzeDuplicateMojo extends AbstractMojo {
51 public static final String MESSAGE_DUPLICATE_DEP_IN_DEPENDENCIES =
52 "List of duplicate dependencies defined in <dependencies/> in your pom.xml:\n";
53
54 public static final String MESSAGE_DUPLICATE_DEP_IN_DEPMGMT =
55 "List of duplicate dependencies defined in <dependencyManagement/> in your pom.xml:\n";
56
57
58
59
60
61
62 @Parameter(property = "mdep.analyze.skip", defaultValue = "false")
63 private boolean skip;
64
65
66
67
68 @Parameter(defaultValue = "${project}", readonly = true, required = true)
69 private MavenProject project;
70
71
72
73
74 @Override
75 public void execute() throws MojoExecutionException, MojoFailureException {
76 if (skip) {
77 getLog().info("Skipping plugin execution");
78 return;
79 }
80
81 MavenXpp3Reader pomReader = new MavenXpp3Reader();
82 Model model;
83 try (Reader reader = ReaderFactory.newXmlReader(project.getFile())) {
84 model = pomReader.read(reader);
85 } catch (IOException | XmlPullParserException e) {
86 throw new MojoExecutionException("Exception: " + e.getMessage(), e);
87 }
88
89 Set<String> duplicateDependencies = Collections.emptySet();
90 if (model.getDependencies() != null) {
91 duplicateDependencies = findDuplicateDependencies(model.getDependencies());
92 }
93
94 Set<String> duplicateDependenciesManagement = Collections.emptySet();
95 if (model.getDependencyManagement() != null
96 && model.getDependencyManagement().getDependencies() != null) {
97 duplicateDependenciesManagement =
98 findDuplicateDependencies(model.getDependencyManagement().getDependencies());
99 }
100
101 if (getLog().isInfoEnabled()) {
102 StringBuilder sb = new StringBuilder();
103
104 createMessage(duplicateDependencies, sb, MESSAGE_DUPLICATE_DEP_IN_DEPENDENCIES);
105 createMessage(duplicateDependenciesManagement, sb, MESSAGE_DUPLICATE_DEP_IN_DEPMGMT);
106
107 if (sb.length() > 0) {
108 getLog().info(sb.toString());
109 } else {
110 getLog().info("No duplicate dependencies found in <dependencies/> or in <dependencyManagement/>");
111 }
112 }
113 }
114
115 private void createMessage(
116 Set<String> duplicateDependencies, StringBuilder sb, String messageDuplicateDepInDependencies) {
117 if (!duplicateDependencies.isEmpty()) {
118 if (sb.length() > 0) {
119 sb.append("\n");
120 }
121 sb.append(messageDuplicateDepInDependencies);
122 for (Iterator<String> it = duplicateDependencies.iterator(); it.hasNext(); ) {
123 String dup = it.next();
124
125 sb.append("\to ").append(dup);
126 if (it.hasNext()) {
127 sb.append("\n");
128 }
129 }
130 }
131 }
132
133 private Set<String> findDuplicateDependencies(List<Dependency> modelDependencies) {
134 List<String> modelDependencies2 =
135 modelDependencies.stream().map(Dependency::getManagementKey).collect(Collectors.toList());
136
137 modelDependencies2.removeIf(new HashSet<>(modelDependencies2)::remove);
138
139 return new LinkedHashSet<>(modelDependencies2);
140 }
141 }