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 try (FileInputStream pomInputStream = new FileInputStream(project.getFile())) {
66 Model model = modelReader.read(pomInputStream, false);
67 maven2Validation(model);
68 } catch (IOException | XmlPullParserException e) {
69 throw new EnforcerRuleError("Unable to retrieve the MavenProject: ", e);
70 }
71 }
72
73 private void maven2Validation(Model model) throws EnforcerRuleException {
74 List<Dependency> dependencies = model.getDependencies();
75 Map<String, Integer> duplicateDependencies = validateDependencies(dependencies);
76
77 int duplicates = duplicateDependencies.size();
78
79 StringBuilder summary = new StringBuilder();
80 messageBuilder(duplicateDependencies, "dependencies.dependency", summary);
81
82 if (model.getDependencyManagement() != null) {
83 List<Dependency> managementDependencies =
84 model.getDependencyManagement().getDependencies();
85 Map<String, Integer> duplicateManagementDependencies = validateDependencies(managementDependencies);
86 duplicates += duplicateManagementDependencies.size();
87
88 messageBuilder(duplicateManagementDependencies, "dependencyManagement.dependencies.dependency", summary);
89 }
90
91 List<Profile> profiles = model.getProfiles();
92 for (Profile profile : profiles) {
93 List<Dependency> profileDependencies = profile.getDependencies();
94
95 Map<String, Integer> duplicateProfileDependencies = validateDependencies(profileDependencies);
96
97 duplicates += duplicateProfileDependencies.size();
98
99 messageBuilder(
100 duplicateProfileDependencies,
101 "profiles.profile[" + profile.getId() + "].dependencies.dependency",
102 summary);
103
104 if (profile.getDependencyManagement() != null) {
105 List<Dependency> profileManagementDependencies =
106 profile.getDependencyManagement().getDependencies();
107
108 Map<String, Integer> duplicateProfileManagementDependencies =
109 validateDependencies(profileManagementDependencies);
110
111 duplicates += duplicateProfileManagementDependencies.size();
112
113 messageBuilder(
114 duplicateProfileManagementDependencies,
115 "profiles.profile[" + profile.getId() + "].dependencyManagement.dependencies.dependency",
116 summary);
117 }
118 }
119
120 if (summary.length() > 0) {
121 StringBuilder message = new StringBuilder();
122 message.append("Found ").append(duplicates).append(" duplicate dependency ");
123 message.append(duplicateDependencies.size() == 1 ? "declaration" : "declarations")
124 .append(" in this project:" + System.lineSeparator());
125 message.append(summary);
126 throw new EnforcerRuleException(message.toString());
127 }
128 }
129
130 private void messageBuilder(Map<String, Integer> duplicateDependencies, String prefix, StringBuilder message) {
131 if (!duplicateDependencies.isEmpty()) {
132 for (Map.Entry<String, Integer> entry : duplicateDependencies.entrySet()) {
133 message.append(" - ")
134 .append(prefix)
135 .append('[')
136 .append(entry.getKey())
137 .append("] (")
138 .append(entry.getValue())
139 .append(" times)" + System.lineSeparator());
140 }
141 }
142 }
143
144 private Map<String, Integer> validateDependencies(List<Dependency> dependencies) {
145 Map<String, Integer> duplicateDeps = new HashMap<>();
146 Set<String> deps = new HashSet<>();
147 for (Dependency dependency : dependencies) {
148 String key = dependency.getManagementKey();
149
150 if (deps.contains(key)) {
151 int times = 1;
152 if (duplicateDeps.containsKey(key)) {
153 times = duplicateDeps.get(key);
154 }
155 duplicateDeps.put(key, times + 1);
156 } else {
157 deps.add(key);
158 }
159 }
160 return duplicateDeps;
161 }
162 }