1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.slf4j.helpers;
26
27 import java.text.MessageFormat;
28 import java.util.HashMap;
29 import java.util.Map;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 final public class MessageFormatter {
99 static final char DELIM_START = '{';
100 static final char DELIM_STOP = '}';
101 static final String DELIM_STR = "{}";
102 private static final char ESCAPE_CHAR = '\\';
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 final public static FormattingTuple format(String messagePattern, Object arg) {
124 return arrayFormat(messagePattern, new Object[] { arg });
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 final public static FormattingTuple format(final String messagePattern, Object arg1, Object arg2) {
151 return arrayFormat(messagePattern, new Object[] { arg1, arg2 });
152 }
153
154 final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray) {
155 Throwable throwableCandidate = MessageFormatter.getThrowableCandidate(argArray);
156 Object[] args = argArray;
157 if (throwableCandidate != null) {
158 args = MessageFormatter.trimmedCopy(argArray);
159 }
160 return arrayFormat(messagePattern, args, throwableCandidate);
161 }
162
163
164
165
166
167
168
169 final public static String basicArrayFormat(final String messagePattern, final Object[] argArray) {
170 FormattingTuple ft = arrayFormat(messagePattern, argArray, null);
171 return ft.getMessage();
172 }
173
174 public static String basicArrayFormat(NormalizedParameters np) {
175 return basicArrayFormat(np.getMessage(), np.getArguments());
176 }
177
178 final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray, Throwable throwable) {
179
180 if (messagePattern == null) {
181 return new FormattingTuple(null, argArray, throwable);
182 }
183
184 if (argArray == null) {
185 return new FormattingTuple(messagePattern);
186 }
187
188 int i = 0;
189 int j;
190
191 StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
192
193 int L;
194 for (L = 0; L < argArray.length; L++) {
195
196 j = messagePattern.indexOf(DELIM_STR, i);
197
198 if (j == -1) {
199
200 if (i == 0) {
201 return new FormattingTuple(messagePattern, argArray, throwable);
202 } else {
203
204 sbuf.append(messagePattern, i, messagePattern.length());
205 return new FormattingTuple(sbuf.toString(), argArray, throwable);
206 }
207 } else {
208 if (isEscapedDelimeter(messagePattern, j)) {
209 if (!isDoubleEscaped(messagePattern, j)) {
210 L--;
211 sbuf.append(messagePattern, i, j - 1);
212 sbuf.append(DELIM_START);
213 i = j + 1;
214 } else {
215
216
217
218 sbuf.append(messagePattern, i, j - 1);
219 deeplyAppendParameter(sbuf, argArray[L], new HashMap<>());
220 i = j + 2;
221 }
222 } else {
223
224 sbuf.append(messagePattern, i, j);
225 deeplyAppendParameter(sbuf, argArray[L], new HashMap<>());
226 i = j + 2;
227 }
228 }
229 }
230
231 sbuf.append(messagePattern, i, messagePattern.length());
232 return new FormattingTuple(sbuf.toString(), argArray, throwable);
233 }
234
235 final static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) {
236
237 if (delimeterStartIndex == 0) {
238 return false;
239 }
240 char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
241 if (potentialEscape == ESCAPE_CHAR) {
242 return true;
243 } else {
244 return false;
245 }
246 }
247
248 final static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {
249 if (delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {
250 return true;
251 } else {
252 return false;
253 }
254 }
255
256
257 private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {
258 if (o == null) {
259 sbuf.append("null");
260 return;
261 }
262 if (!o.getClass().isArray()) {
263 safeObjectAppend(sbuf, o);
264 } else {
265
266
267 if (o instanceof boolean[]) {
268 booleanArrayAppend(sbuf, (boolean[]) o);
269 } else if (o instanceof byte[]) {
270 byteArrayAppend(sbuf, (byte[]) o);
271 } else if (o instanceof char[]) {
272 charArrayAppend(sbuf, (char[]) o);
273 } else if (o instanceof short[]) {
274 shortArrayAppend(sbuf, (short[]) o);
275 } else if (o instanceof int[]) {
276 intArrayAppend(sbuf, (int[]) o);
277 } else if (o instanceof long[]) {
278 longArrayAppend(sbuf, (long[]) o);
279 } else if (o instanceof float[]) {
280 floatArrayAppend(sbuf, (float[]) o);
281 } else if (o instanceof double[]) {
282 doubleArrayAppend(sbuf, (double[]) o);
283 } else {
284 objectArrayAppend(sbuf, (Object[]) o, seenMap);
285 }
286 }
287 }
288
289 private static void safeObjectAppend(StringBuilder sbuf, Object o) {
290 try {
291 String oAsString = o.toString();
292 sbuf.append(oAsString);
293 } catch (Throwable t) {
294 Util.report("SLF4J: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]", t);
295 sbuf.append("[FAILED toString()]");
296 }
297
298 }
299
300 private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {
301 sbuf.append('[');
302 if (!seenMap.containsKey(a)) {
303 seenMap.put(a, null);
304 final int len = a.length;
305 for (int i = 0; i < len; i++) {
306 deeplyAppendParameter(sbuf, a[i], seenMap);
307 if (i != len - 1)
308 sbuf.append(", ");
309 }
310
311 seenMap.remove(a);
312 } else {
313 sbuf.append("...");
314 }
315 sbuf.append(']');
316 }
317
318 private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
319 sbuf.append('[');
320 final int len = a.length;
321 for (int i = 0; i < len; i++) {
322 sbuf.append(a[i]);
323 if (i != len - 1)
324 sbuf.append(", ");
325 }
326 sbuf.append(']');
327 }
328
329 private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
330 sbuf.append('[');
331 final int len = a.length;
332 for (int i = 0; i < len; i++) {
333 sbuf.append(a[i]);
334 if (i != len - 1)
335 sbuf.append(", ");
336 }
337 sbuf.append(']');
338 }
339
340 private static void charArrayAppend(StringBuilder sbuf, char[] a) {
341 sbuf.append('[');
342 final int len = a.length;
343 for (int i = 0; i < len; i++) {
344 sbuf.append(a[i]);
345 if (i != len - 1)
346 sbuf.append(", ");
347 }
348 sbuf.append(']');
349 }
350
351 private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
352 sbuf.append('[');
353 final int len = a.length;
354 for (int i = 0; i < len; i++) {
355 sbuf.append(a[i]);
356 if (i != len - 1)
357 sbuf.append(", ");
358 }
359 sbuf.append(']');
360 }
361
362 private static void intArrayAppend(StringBuilder sbuf, int[] a) {
363 sbuf.append('[');
364 final int len = a.length;
365 for (int i = 0; i < len; i++) {
366 sbuf.append(a[i]);
367 if (i != len - 1)
368 sbuf.append(", ");
369 }
370 sbuf.append(']');
371 }
372
373 private static void longArrayAppend(StringBuilder sbuf, long[] a) {
374 sbuf.append('[');
375 final int len = a.length;
376 for (int i = 0; i < len; i++) {
377 sbuf.append(a[i]);
378 if (i != len - 1)
379 sbuf.append(", ");
380 }
381 sbuf.append(']');
382 }
383
384 private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
385 sbuf.append('[');
386 final int len = a.length;
387 for (int i = 0; i < len; i++) {
388 sbuf.append(a[i]);
389 if (i != len - 1)
390 sbuf.append(", ");
391 }
392 sbuf.append(']');
393 }
394
395 private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
396 sbuf.append('[');
397 final int len = a.length;
398 for (int i = 0; i < len; i++) {
399 sbuf.append(a[i]);
400 if (i != len - 1)
401 sbuf.append(", ");
402 }
403 sbuf.append(']');
404 }
405
406
407
408
409
410
411
412
413
414 public static Throwable getThrowableCandidate(final Object[] argArray) {
415 return NormalizedParameters.getThrowableCandidate(argArray);
416 }
417
418
419
420
421
422
423
424
425
426 public static Object[] trimmedCopy(final Object[] argArray) {
427 return NormalizedParameters.trimmedCopy(argArray);
428 }
429
430 }