1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.enforcer.rules;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import java.util.Set;
32
33 import org.apache.maven.enforcer.rule.api.EnforcerRuleError;
34 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
35 import org.apache.maven.model.Dependency;
36 import org.apache.maven.model.Model;
37 import org.apache.maven.model.Profile;
38 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
39 import org.apache.maven.project.MavenProject;
40 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
41
42
43
44
45
46
47
48
49 @Named("banDuplicatePomDependencyVersions")
50 public final class BanDuplicatePomDependencyVersions extends AbstractStandardEnforcerRule {
51
52 private final MavenProject project;
53
54 @Inject
55 public BanDuplicatePomDependencyVersions(MavenProject project) {
56 this.project = Objects.requireNonNull(project);
57 }
58
59 @Override
60 public void execute() throws EnforcerRuleException {
61
62
63 MavenXpp3Reader modelReader = new MavenXpp3Reader();
64
65 Model model;
66 try (FileInputStream pomInputStream = new FileInputStream(project.getFile())) {
67 model = modelReader.read(pomInputStream, false);
68 } catch (IOException | XmlPullParserException e) {
69 throw new EnforcerRuleError("Unable to retrieve the MavenProject: ", e);
70 }
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 maven2Validation(model);
87
88
89
90
91 }
92
93 private void maven2Validation(Model model) throws EnforcerRuleException {
94 List<Dependency> dependencies = model.getDependencies();
95 Map<String, Integer> duplicateDependencies = validateDependencies(dependencies);
96
97 int duplicates = duplicateDependencies.size();
98
99 StringBuilder summary = new StringBuilder();
100 messageBuilder(duplicateDependencies, "dependencies.dependency", summary);
101
102 if (model.getDependencyManagement() != null) {
103 List<Dependency> managementDependencies =
104 model.getDependencyManagement().getDependencies();
105 Map<String, Integer> duplicateManagementDependencies = validateDependencies(managementDependencies);
106 duplicates += duplicateManagementDependencies.size();
107
108 messageBuilder(duplicateManagementDependencies, "dependencyManagement.dependencies.dependency", summary);
109 }
110
111 List<Profile> profiles = model.getProfiles();
112 for (Profile profile : profiles) {
113 List<Dependency> profileDependencies = profile.getDependencies();
114
115 Map<String, Integer> duplicateProfileDependencies = validateDependencies(profileDependencies);
116
117 duplicates += duplicateProfileDependencies.size();
118
119 messageBuilder(
120 duplicateProfileDependencies,
121 "profiles.profile[" + profile.getId() + "].dependencies.dependency",
122 summary);
123
124 if (profile.getDependencyManagement() != null) {
125 List<Dependency> profileManagementDependencies =
126 profile.getDependencyManagement().getDependencies();
127
128 Map<String, Integer> duplicateProfileManagementDependencies =
129 validateDependencies(profileManagementDependencies);
130
131 duplicates += duplicateProfileManagementDependencies.size();
132
133 messageBuilder(
134 duplicateProfileManagementDependencies,
135 "profiles.profile[" + profile.getId() + "].dependencyManagement.dependencies.dependency",
136 summary);
137 }
138 }
139
140 if (summary.length() > 0) {
141 StringBuilder message = new StringBuilder();
142 message.append("Found ").append(duplicates).append(" duplicate dependency ");
143 message.append(duplicateDependencies.size() == 1 ? "declaration" : "declarations")
144 .append(" in this project:" + System.lineSeparator());
145 message.append(summary);
146 throw new EnforcerRuleException(message.toString());
147 }
148 }
149
150 private void messageBuilder(Map<String, Integer> duplicateDependencies, String prefix, StringBuilder message) {
151 if (!duplicateDependencies.isEmpty()) {
152 for (Map.Entry<String, Integer> entry : duplicateDependencies.entrySet()) {
153 message.append(" - ")
154 .append(prefix)
155 .append('[')
156 .append(entry.getKey())
157 .append("] (")
158 .append(entry.getValue())
159 .append(" times)" + System.lineSeparator());
160 }
161 }
162 }
163
164 private Map<String, Integer> validateDependencies(List<Dependency> dependencies) {
165 Map<String, Integer> duplicateDeps = new HashMap<>();
166 Set<String> deps = new HashSet<>();
167 for (Dependency dependency : dependencies) {
168 String key = dependency.getManagementKey();
169
170 if (deps.contains(key)) {
171 int times = 1;
172 if (duplicateDeps.containsKey(key)) {
173 times = duplicateDeps.get(key);
174 }
175 duplicateDeps.put(key, times + 1);
176 } else {
177 deps.add(key);
178 }
179 }
180 return duplicateDeps;
181 }
182 }