1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.compiler;
20
21 import javax.tools.Diagnostic;
22 import javax.tools.DiagnosticListener;
23 import javax.tools.JavaFileObject;
24
25 import java.util.Arrays;
26 import java.util.LinkedHashMap;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.Optional;
30
31 import org.apache.maven.api.plugin.Log;
32 import org.apache.maven.api.services.MessageBuilder;
33 import org.apache.maven.api.services.MessageBuilderFactory;
34
35
36
37
38
39
40 final class DiagnosticLogger implements DiagnosticListener<JavaFileObject> {
41
42
43
44 private final Log logger;
45
46
47
48
49 private final MessageBuilderFactory messageBuilderFactory;
50
51
52
53
54 private final Locale locale;
55
56
57
58
59 private int numErrors, numWarnings;
60
61
62
63
64 private final Map<String, Integer> codeCount;
65
66
67
68
69 private String firstError;
70
71
72
73
74
75
76
77
78 DiagnosticLogger(Log logger, MessageBuilderFactory messageBuilderFactory, Locale locale) {
79 this.logger = logger;
80 this.messageBuilderFactory = messageBuilderFactory;
81 this.locale = locale;
82 codeCount = new LinkedHashMap<>();
83 }
84
85
86
87
88
89
90 @Override
91 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
92 MessageBuilder record = messageBuilderFactory.builder();
93 String message = diagnostic.getMessage(locale);
94 record.a(message);
95 Diagnostic.Kind kind = diagnostic.getKind();
96 String style;
97 switch (kind) {
98 case ERROR:
99 style = ".error:-bold,f:red";
100 break;
101 case MANDATORY_WARNING:
102 case WARNING:
103 style = ".warning:-bold,f:yellow";
104 break;
105 default:
106 style = ".info:-bold,f:blue";
107 break;
108 }
109 JavaFileObject source = diagnostic.getSource();
110 if (source != null) {
111 record.newline().a(" at ").a(source.getName());
112 long line = diagnostic.getLineNumber();
113 long column = diagnostic.getColumnNumber();
114 if (line != Diagnostic.NOPOS || column != Diagnostic.NOPOS) {
115 record.style(style).a('[');
116 if (line != Diagnostic.NOPOS) {
117 record.a(line);
118 }
119 if (column != Diagnostic.NOPOS) {
120 record.a(',').a(column);
121 }
122 record.a(']').resetStyle();
123 }
124 }
125 String log = record.toString();
126 switch (kind) {
127 case ERROR:
128 if (firstError == null) {
129 firstError = message;
130 }
131 logger.error(log);
132 numErrors++;
133 break;
134 case MANDATORY_WARNING:
135 case WARNING:
136 logger.warn(log);
137 numWarnings++;
138 break;
139 default:
140 logger.info(log);
141 break;
142 }
143
144 String code = diagnostic.getCode();
145 if (code != null) {
146 codeCount.merge(code, 1, (old, initial) -> old + 1);
147 }
148 }
149
150
151
152
153
154
155 Optional<String> firstError(Exception cause) {
156 return Optional.ofNullable(cause != null && firstError == null ? cause.getMessage() : firstError);
157 }
158
159
160
161
162 void logSummary() {
163 MessageBuilder message = messageBuilderFactory.builder();
164 final String patternForCount;
165 if (!codeCount.isEmpty()) {
166 @SuppressWarnings("unchecked")
167 Map.Entry<String, Integer>[] entries = codeCount.entrySet().toArray(Map.Entry[]::new);
168 Arrays.sort(entries, (a, b) -> Integer.compare(b.getValue(), a.getValue()));
169 patternForCount = patternForCount(Math.max(entries[0].getValue(), Math.max(numWarnings, numErrors)));
170 message.strong("Summary of compiler messages:").newline();
171 for (Map.Entry<String, Integer> entry : entries) {
172 int count = entry.getValue();
173 message.format(patternForCount, count, entry.getKey()).newline();
174 }
175 } else {
176 patternForCount = patternForCount(Math.max(numWarnings, numErrors));
177 }
178 if ((numWarnings | numErrors) != 0) {
179 message.strong("Total:").newline();
180 }
181 if (numWarnings != 0) {
182 writeCount(message, patternForCount, numWarnings, "warning");
183 }
184 if (numErrors != 0) {
185 writeCount(message, patternForCount, numErrors, "error");
186 }
187 logger.info(message.toString());
188 }
189
190
191
192
193
194
195 private static String patternForCount(int n) {
196 return " %" + Integer.toString(n).length() + "d %s";
197 }
198
199
200
201
202 private static void writeCount(MessageBuilder message, String patternForCount, int count, String name) {
203 message.format(patternForCount, count, name);
204 if (count > 1) {
205 message.append('s');
206 }
207 message.newline();
208 }
209 }