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,
151 Object arg1, Object arg2) {
152 return arrayFormat(messagePattern, new Object[] { arg1, arg2 });
153 }
154
155 static final Throwable getThrowableCandidate(Object[] argArray) {
156 if (argArray == null || argArray.length == 0) {
157 return null;
158 }
159
160 final Object lastEntry = argArray[argArray.length - 1];
161 if (lastEntry instanceof Throwable) {
162 return (Throwable) lastEntry;
163 }
164 return null;
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179 final public static FormattingTuple arrayFormat(final String messagePattern,
180 final Object[] argArray) {
181
182 Throwable throwableCandidate = getThrowableCandidate(argArray);
183
184 if (messagePattern == null) {
185 return new FormattingTuple(null, argArray, throwableCandidate);
186 }
187
188 if (argArray == null) {
189 return new FormattingTuple(messagePattern);
190 }
191
192 int i = 0;
193 int j;
194
195 StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
196
197 int L;
198 for (L = 0; L < argArray.length; L++) {
199
200 j = messagePattern.indexOf(DELIM_STR, i);
201
202 if (j == -1) {
203
204 if (i == 0) {
205 return new FormattingTuple(messagePattern, argArray,
206 throwableCandidate);
207 } else {
208
209 sbuf.append(messagePattern.substring(i, messagePattern.length()));
210 return new FormattingTuple(sbuf.toString(), argArray,
211 throwableCandidate);
212 }
213 } else {
214 if (isEscapedDelimeter(messagePattern, j)) {
215 if (!isDoubleEscaped(messagePattern, j)) {
216 L--;
217 sbuf.append(messagePattern.substring(i, j - 1));
218 sbuf.append(DELIM_START);
219 i = j + 1;
220 } else {
221
222
223
224 sbuf.append(messagePattern.substring(i, j - 1));
225 deeplyAppendParameter(sbuf, argArray[L], new HashMap());
226 i = j + 2;
227 }
228 } else {
229
230 sbuf.append(messagePattern.substring(i, j));
231 deeplyAppendParameter(sbuf, argArray[L], new HashMap());
232 i = j + 2;
233 }
234 }
235 }
236
237 sbuf.append(messagePattern.substring(i, messagePattern.length()));
238 if (L < argArray.length - 1) {
239 return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate);
240 } else {
241 return new FormattingTuple(sbuf.toString(), argArray, null);
242 }
243 }
244
245 final static boolean isEscapedDelimeter(String messagePattern,
246 int delimeterStartIndex) {
247
248 if (delimeterStartIndex == 0) {
249 return false;
250 }
251 char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
252 if (potentialEscape == ESCAPE_CHAR) {
253 return true;
254 } else {
255 return false;
256 }
257 }
258
259 final static boolean isDoubleEscaped(String messagePattern,
260 int delimeterStartIndex) {
261 if (delimeterStartIndex >= 2
262 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {
263 return true;
264 } else {
265 return false;
266 }
267 }
268
269
270 private static void deeplyAppendParameter(StringBuilder sbuf, Object o,
271 Map seenMap) {
272 if (o == null) {
273 sbuf.append("null");
274 return;
275 }
276 if (!o.getClass().isArray()) {
277 safeObjectAppend(sbuf, o);
278 } else {
279
280
281 if (o instanceof boolean[]) {
282 booleanArrayAppend(sbuf, (boolean[]) o);
283 } else if (o instanceof byte[]) {
284 byteArrayAppend(sbuf, (byte[]) o);
285 } else if (o instanceof char[]) {
286 charArrayAppend(sbuf, (char[]) o);
287 } else if (o instanceof short[]) {
288 shortArrayAppend(sbuf, (short[]) o);
289 } else if (o instanceof int[]) {
290 intArrayAppend(sbuf, (int[]) o);
291 } else if (o instanceof long[]) {
292 longArrayAppend(sbuf, (long[]) o);
293 } else if (o instanceof float[]) {
294 floatArrayAppend(sbuf, (float[]) o);
295 } else if (o instanceof double[]) {
296 doubleArrayAppend(sbuf, (double[]) o);
297 } else {
298 objectArrayAppend(sbuf, (Object[]) o, seenMap);
299 }
300 }
301 }
302
303 private static void safeObjectAppend(StringBuilder sbuf, Object o) {
304 try {
305 String oAsString = o.toString();
306 sbuf.append(oAsString);
307 } catch (Throwable t) {
308 System.err
309 .println("SLF4J: Failed toString() invocation on an object of type ["
310 + o.getClass().getName() + "]");
311 t.printStackTrace();
312 sbuf.append("[FAILED toString()]");
313 }
314
315 }
316
317 private static void objectArrayAppend(StringBuilder sbuf, Object[] a,
318 Map seenMap) {
319 sbuf.append('[');
320 if (!seenMap.containsKey(a)) {
321 seenMap.put(a, null);
322 final int len = a.length;
323 for (int i = 0; i < len; i++) {
324 deeplyAppendParameter(sbuf, a[i], seenMap);
325 if (i != len - 1)
326 sbuf.append(", ");
327 }
328
329 seenMap.remove(a);
330 } else {
331 sbuf.append("...");
332 }
333 sbuf.append(']');
334 }
335
336 private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
337 sbuf.append('[');
338 final int len = a.length;
339 for (int i = 0; i < len; i++) {
340 sbuf.append(a[i]);
341 if (i != len - 1)
342 sbuf.append(", ");
343 }
344 sbuf.append(']');
345 }
346
347 private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
348 sbuf.append('[');
349 final int len = a.length;
350 for (int i = 0; i < len; i++) {
351 sbuf.append(a[i]);
352 if (i != len - 1)
353 sbuf.append(", ");
354 }
355 sbuf.append(']');
356 }
357
358 private static void charArrayAppend(StringBuilder sbuf, char[] a) {
359 sbuf.append('[');
360 final int len = a.length;
361 for (int i = 0; i < len; i++) {
362 sbuf.append(a[i]);
363 if (i != len - 1)
364 sbuf.append(", ");
365 }
366 sbuf.append(']');
367 }
368
369 private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
370 sbuf.append('[');
371 final int len = a.length;
372 for (int i = 0; i < len; i++) {
373 sbuf.append(a[i]);
374 if (i != len - 1)
375 sbuf.append(", ");
376 }
377 sbuf.append(']');
378 }
379
380 private static void intArrayAppend(StringBuilder sbuf, int[] a) {
381 sbuf.append('[');
382 final int len = a.length;
383 for (int i = 0; i < len; i++) {
384 sbuf.append(a[i]);
385 if (i != len - 1)
386 sbuf.append(", ");
387 }
388 sbuf.append(']');
389 }
390
391 private static void longArrayAppend(StringBuilder sbuf, long[] a) {
392 sbuf.append('[');
393 final int len = a.length;
394 for (int i = 0; i < len; i++) {
395 sbuf.append(a[i]);
396 if (i != len - 1)
397 sbuf.append(", ");
398 }
399 sbuf.append(']');
400 }
401
402 private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
403 sbuf.append('[');
404 final int len = a.length;
405 for (int i = 0; i < len; i++) {
406 sbuf.append(a[i]);
407 if (i != len - 1)
408 sbuf.append(", ");
409 }
410 sbuf.append(']');
411 }
412
413 private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
414 sbuf.append('[');
415 final int len = a.length;
416 for (int i = 0; i < len; i++) {
417 sbuf.append(a[i]);
418 if (i != len - 1)
419 sbuf.append(", ");
420 }
421 sbuf.append(']');
422 }
423 }