001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.lang3.builder;
018
019 import java.io.Serializable;
020 import java.lang.reflect.Array;
021 import java.util.Collection;
022 import java.util.Map;
023 import java.util.WeakHashMap;
024
025 import org.apache.commons.lang3.ClassUtils;
026 import org.apache.commons.lang3.ObjectUtils;
027 import org.apache.commons.lang3.SystemUtils;
028
029 /**
030 * <p>Controls <code>String</code> formatting for {@link ToStringBuilder}.
031 * The main public interface is always via <code>ToStringBuilder</code>.</p>
032 *
033 * <p>These classes are intended to be used as <code>Singletons</code>.
034 * There is no need to instantiate a new style each time. A program
035 * will generally use one of the predefined constants on this class.
036 * Alternatively, the {@link StandardToStringStyle} class can be used
037 * to set the individual settings. Thus most styles can be achieved
038 * without subclassing.</p>
039 *
040 * <p>If required, a subclass can override as many or as few of the
041 * methods as it requires. Each object type (from <code>boolean</code>
042 * to <code>long</code> to <code>Object</code> to <code>int[]</code>) has
043 * its own methods to output it. Most have two versions, detail and summary.
044 *
045 * <p>For example, the detail version of the array based methods will
046 * output the whole array, whereas the summary method will just output
047 * the array length.</p>
048 *
049 * <p>If you want to format the output of certain objects, such as dates, you
050 * must create a subclass and override a method.
051 * <pre>
052 * public class MyStyle extends ToStringStyle {
053 * protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
054 * if (value instanceof Date) {
055 * value = new SimpleDateFormat("yyyy-MM-dd").format(value);
056 * }
057 * buffer.append(value);
058 * }
059 * }
060 * </pre>
061 * </p>
062 *
063 * @since 1.0
064 * @version $Id: ToStringStyle.java 1091066 2011-04-11 13:30:11Z mbenson $
065 */
066 public abstract class ToStringStyle implements Serializable {
067
068 /**
069 * Serialization version ID.
070 */
071 private static final long serialVersionUID = -2587890625525655916L;
072
073 /**
074 * The default toString style. Using the Using the <code>Person</code>
075 * example from {@link ToStringBuilder}, the output would look like this:
076 *
077 * <pre>
078 * Person@182f0db[name=John Doe,age=33,smoker=false]
079 * </pre>
080 */
081 public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle();
082
083 /**
084 * The multi line toString style. Using the Using the <code>Person</code>
085 * example from {@link ToStringBuilder}, the output would look like this:
086 *
087 * <pre>
088 * Person@182f0db[
089 * name=John Doe
090 * age=33
091 * smoker=false
092 * ]
093 * </pre>
094 */
095 public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle();
096
097 /**
098 * The no field names toString style. Using the Using the
099 * <code>Person</code> example from {@link ToStringBuilder}, the output
100 * would look like this:
101 *
102 * <pre>
103 * Person@182f0db[John Doe,33,false]
104 * </pre>
105 */
106 public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle();
107
108 /**
109 * The short prefix toString style. Using the <code>Person</code> example
110 * from {@link ToStringBuilder}, the output would look like this:
111 *
112 * <pre>
113 * Person[name=John Doe,age=33,smoker=false]
114 * </pre>
115 *
116 * @since 2.1
117 */
118 public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle();
119
120 /**
121 * The simple toString style. Using the Using the <code>Person</code>
122 * example from {@link ToStringBuilder}, the output would look like this:
123 *
124 * <pre>
125 * John Doe,33,false
126 * </pre>
127 */
128 public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle();
129
130 /**
131 * <p>
132 * A registry of objects used by <code>reflectionToString</code> methods
133 * to detect cyclical object references and avoid infinite loops.
134 * </p>
135 */
136 private static final ThreadLocal<WeakHashMap<Object, Object>> REGISTRY =
137 new ThreadLocal<WeakHashMap<Object,Object>>();
138
139 /**
140 * <p>
141 * Returns the registry of objects being traversed by the <code>reflectionToString</code>
142 * methods in the current thread.
143 * </p>
144 *
145 * @return Set the registry of objects being traversed
146 */
147 static Map<Object, Object> getRegistry() {
148 return REGISTRY.get();
149 }
150
151 /**
152 * <p>
153 * Returns <code>true</code> if the registry contains the given object.
154 * Used by the reflection methods to avoid infinite loops.
155 * </p>
156 *
157 * @param value
158 * The object to lookup in the registry.
159 * @return boolean <code>true</code> if the registry contains the given
160 * object.
161 */
162 static boolean isRegistered(Object value) {
163 Map<Object, Object> m = getRegistry();
164 return m != null && m.containsKey(value);
165 }
166
167 /**
168 * <p>
169 * Registers the given object. Used by the reflection methods to avoid
170 * infinite loops.
171 * </p>
172 *
173 * @param value
174 * The object to register.
175 */
176 static void register(Object value) {
177 if (value != null) {
178 Map<Object, Object> m = getRegistry();
179 if (m == null) {
180 REGISTRY.set(new WeakHashMap<Object, Object>());
181 }
182 getRegistry().put(value, null);
183 }
184 }
185
186 /**
187 * <p>
188 * Unregisters the given object.
189 * </p>
190 *
191 * <p>
192 * Used by the reflection methods to avoid infinite loops.
193 * </p>
194 *
195 * @param value
196 * The object to unregister.
197 */
198 static void unregister(Object value) {
199 if (value != null) {
200 Map<Object, Object> m = getRegistry();
201 if (m != null) {
202 m.remove(value);
203 if (m.isEmpty()) {
204 REGISTRY.remove();
205 }
206 }
207 }
208 }
209
210 /**
211 * Whether to use the field names, the default is <code>true</code>.
212 */
213 private boolean useFieldNames = true;
214
215 /**
216 * Whether to use the class name, the default is <code>true</code>.
217 */
218 private boolean useClassName = true;
219
220 /**
221 * Whether to use short class names, the default is <code>false</code>.
222 */
223 private boolean useShortClassName = false;
224
225 /**
226 * Whether to use the identity hash code, the default is <code>true</code>.
227 */
228 private boolean useIdentityHashCode = true;
229
230 /**
231 * The content start <code>'['</code>.
232 */
233 private String contentStart = "[";
234
235 /**
236 * The content end <code>']'</code>.
237 */
238 private String contentEnd = "]";
239
240 /**
241 * The field name value separator <code>'='</code>.
242 */
243 private String fieldNameValueSeparator = "=";
244
245 /**
246 * Whether the field separator should be added before any other fields.
247 */
248 private boolean fieldSeparatorAtStart = false;
249
250 /**
251 * Whether the field separator should be added after any other fields.
252 */
253 private boolean fieldSeparatorAtEnd = false;
254
255 /**
256 * The field separator <code>','</code>.
257 */
258 private String fieldSeparator = ",";
259
260 /**
261 * The array start <code>'{'</code>.
262 */
263 private String arrayStart = "{";
264
265 /**
266 * The array separator <code>','</code>.
267 */
268 private String arraySeparator = ",";
269
270 /**
271 * The detail for array content.
272 */
273 private boolean arrayContentDetail = true;
274
275 /**
276 * The array end <code>'}'</code>.
277 */
278 private String arrayEnd = "}";
279
280 /**
281 * The value to use when fullDetail is <code>null</code>,
282 * the default value is <code>true</code>.
283 */
284 private boolean defaultFullDetail = true;
285
286 /**
287 * The <code>null</code> text <code>'<null>'</code>.
288 */
289 private String nullText = "<null>";
290
291 /**
292 * The summary size text start <code>'<size'</code>.
293 */
294 private String sizeStartText = "<size=";
295
296 /**
297 * The summary size text start <code>'>'</code>.
298 */
299 private String sizeEndText = ">";
300
301 /**
302 * The summary object text start <code>'<'</code>.
303 */
304 private String summaryObjectStartText = "<";
305
306 /**
307 * The summary object text start <code>'>'</code>.
308 */
309 private String summaryObjectEndText = ">";
310
311 //----------------------------------------------------------------------------
312
313 /**
314 * <p>Constructor.</p>
315 */
316 protected ToStringStyle() {
317 super();
318 }
319
320 //----------------------------------------------------------------------------
321
322 /**
323 * <p>Append to the <code>toString</code> the superclass toString.</p>
324 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
325 *
326 * <p>A <code>null</code> <code>superToString</code> is ignored.</p>
327 *
328 * @param buffer the <code>StringBuffer</code> to populate
329 * @param superToString the <code>super.toString()</code>
330 * @since 2.0
331 */
332 public void appendSuper(StringBuffer buffer, String superToString) {
333 appendToString(buffer, superToString);
334 }
335
336 /**
337 * <p>Append to the <code>toString</code> another toString.</p>
338 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
339 *
340 * <p>A <code>null</code> <code>toString</code> is ignored.</p>
341 *
342 * @param buffer the <code>StringBuffer</code> to populate
343 * @param toString the additional <code>toString</code>
344 * @since 2.0
345 */
346 public void appendToString(StringBuffer buffer, String toString) {
347 if (toString != null) {
348 int pos1 = toString.indexOf(contentStart) + contentStart.length();
349 int pos2 = toString.lastIndexOf(contentEnd);
350 if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
351 String data = toString.substring(pos1, pos2);
352 if (fieldSeparatorAtStart) {
353 removeLastFieldSeparator(buffer);
354 }
355 buffer.append(data);
356 appendFieldSeparator(buffer);
357 }
358 }
359 }
360
361 /**
362 * <p>Append to the <code>toString</code> the start of data indicator.</p>
363 *
364 * @param buffer the <code>StringBuffer</code> to populate
365 * @param object the <code>Object</code> to build a <code>toString</code> for
366 */
367 public void appendStart(StringBuffer buffer, Object object) {
368 if (object != null) {
369 appendClassName(buffer, object);
370 appendIdentityHashCode(buffer, object);
371 appendContentStart(buffer);
372 if (fieldSeparatorAtStart) {
373 appendFieldSeparator(buffer);
374 }
375 }
376 }
377
378 /**
379 * <p>Append to the <code>toString</code> the end of data indicator.</p>
380 *
381 * @param buffer the <code>StringBuffer</code> to populate
382 * @param object the <code>Object</code> to build a
383 * <code>toString</code> for.
384 */
385 public void appendEnd(StringBuffer buffer, Object object) {
386 if (this.fieldSeparatorAtEnd == false) {
387 removeLastFieldSeparator(buffer);
388 }
389 appendContentEnd(buffer);
390 unregister(object);
391 }
392
393 /**
394 * <p>Remove the last field separator from the buffer.</p>
395 *
396 * @param buffer the <code>StringBuffer</code> to populate
397 * @since 2.0
398 */
399 protected void removeLastFieldSeparator(StringBuffer buffer) {
400 int len = buffer.length();
401 int sepLen = fieldSeparator.length();
402 if (len > 0 && sepLen > 0 && len >= sepLen) {
403 boolean match = true;
404 for (int i = 0; i < sepLen; i++) {
405 if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
406 match = false;
407 break;
408 }
409 }
410 if (match) {
411 buffer.setLength(len - sepLen);
412 }
413 }
414 }
415
416 //----------------------------------------------------------------------------
417
418 /**
419 * <p>Append to the <code>toString</code> an <code>Object</code>
420 * value, printing the full <code>toString</code> of the
421 * <code>Object</code> passed in.</p>
422 *
423 * @param buffer the <code>StringBuffer</code> to populate
424 * @param fieldName the field name
425 * @param value the value to add to the <code>toString</code>
426 * @param fullDetail <code>true</code> for detail, <code>false</code>
427 * for summary info, <code>null</code> for style decides
428 */
429 public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
430 appendFieldStart(buffer, fieldName);
431
432 if (value == null) {
433 appendNullText(buffer, fieldName);
434
435 } else {
436 appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
437 }
438
439 appendFieldEnd(buffer, fieldName);
440 }
441
442 /**
443 * <p>Append to the <code>toString</code> an <code>Object</code>,
444 * correctly interpreting its type.</p>
445 *
446 * <p>This method performs the main lookup by Class type to correctly
447 * route arrays, <code>Collections</code>, <code>Maps</code> and
448 * <code>Objects</code> to the appropriate method.</p>
449 *
450 * <p>Either detail or summary views can be specified.</p>
451 *
452 * <p>If a cycle is detected, an object will be appended with the
453 * <code>Object.toString()</code> format.</p>
454 *
455 * @param buffer the <code>StringBuffer</code> to populate
456 * @param fieldName the field name, typically not used as already appended
457 * @param value the value to add to the <code>toString</code>,
458 * not <code>null</code>
459 * @param detail output detail or not
460 */
461 protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
462 if (isRegistered(value)
463 && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
464 appendCyclicObject(buffer, fieldName, value);
465 return;
466 }
467
468 register(value);
469
470 try {
471 if (value instanceof Collection<?>) {
472 if (detail) {
473 appendDetail(buffer, fieldName, (Collection<?>) value);
474 } else {
475 appendSummarySize(buffer, fieldName, ((Collection<?>) value).size());
476 }
477
478 } else if (value instanceof Map<?, ?>) {
479 if (detail) {
480 appendDetail(buffer, fieldName, (Map<?, ?>) value);
481 } else {
482 appendSummarySize(buffer, fieldName, ((Map<?, ?>) value).size());
483 }
484
485 } else if (value instanceof long[]) {
486 if (detail) {
487 appendDetail(buffer, fieldName, (long[]) value);
488 } else {
489 appendSummary(buffer, fieldName, (long[]) value);
490 }
491
492 } else if (value instanceof int[]) {
493 if (detail) {
494 appendDetail(buffer, fieldName, (int[]) value);
495 } else {
496 appendSummary(buffer, fieldName, (int[]) value);
497 }
498
499 } else if (value instanceof short[]) {
500 if (detail) {
501 appendDetail(buffer, fieldName, (short[]) value);
502 } else {
503 appendSummary(buffer, fieldName, (short[]) value);
504 }
505
506 } else if (value instanceof byte[]) {
507 if (detail) {
508 appendDetail(buffer, fieldName, (byte[]) value);
509 } else {
510 appendSummary(buffer, fieldName, (byte[]) value);
511 }
512
513 } else if (value instanceof char[]) {
514 if (detail) {
515 appendDetail(buffer, fieldName, (char[]) value);
516 } else {
517 appendSummary(buffer, fieldName, (char[]) value);
518 }
519
520 } else if (value instanceof double[]) {
521 if (detail) {
522 appendDetail(buffer, fieldName, (double[]) value);
523 } else {
524 appendSummary(buffer, fieldName, (double[]) value);
525 }
526
527 } else if (value instanceof float[]) {
528 if (detail) {
529 appendDetail(buffer, fieldName, (float[]) value);
530 } else {
531 appendSummary(buffer, fieldName, (float[]) value);
532 }
533
534 } else if (value instanceof boolean[]) {
535 if (detail) {
536 appendDetail(buffer, fieldName, (boolean[]) value);
537 } else {
538 appendSummary(buffer, fieldName, (boolean[]) value);
539 }
540
541 } else if (value.getClass().isArray()) {
542 if (detail) {
543 appendDetail(buffer, fieldName, (Object[]) value);
544 } else {
545 appendSummary(buffer, fieldName, (Object[]) value);
546 }
547
548 } else {
549 if (detail) {
550 appendDetail(buffer, fieldName, value);
551 } else {
552 appendSummary(buffer, fieldName, value);
553 }
554 }
555 } finally {
556 unregister(value);
557 }
558 }
559
560 /**
561 * <p>Append to the <code>toString</code> an <code>Object</code>
562 * value that has been detected to participate in a cycle. This
563 * implementation will print the standard string value of the value.</p>
564 *
565 * @param buffer the <code>StringBuffer</code> to populate
566 * @param fieldName the field name, typically not used as already appended
567 * @param value the value to add to the <code>toString</code>,
568 * not <code>null</code>
569 *
570 * @since 2.2
571 */
572 protected void appendCyclicObject(StringBuffer buffer, String fieldName, Object value) {
573 ObjectUtils.identityToString(buffer, value);
574 }
575
576 /**
577 * <p>Append to the <code>toString</code> an <code>Object</code>
578 * value, printing the full detail of the <code>Object</code>.</p>
579 *
580 * @param buffer the <code>StringBuffer</code> to populate
581 * @param fieldName the field name, typically not used as already appended
582 * @param value the value to add to the <code>toString</code>,
583 * not <code>null</code>
584 */
585 protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
586 buffer.append(value);
587 }
588
589 /**
590 * <p>Append to the <code>toString</code> a <code>Collection</code>.</p>
591 *
592 * @param buffer the <code>StringBuffer</code> to populate
593 * @param fieldName the field name, typically not used as already appended
594 * @param coll the <code>Collection</code> to add to the
595 * <code>toString</code>, not <code>null</code>
596 */
597 protected void appendDetail(StringBuffer buffer, String fieldName, Collection<?> coll) {
598 buffer.append(coll);
599 }
600
601 /**
602 * <p>Append to the <code>toString</code> a <code>Map<code>.</p>
603 *
604 * @param buffer the <code>StringBuffer</code> to populate
605 * @param fieldName the field name, typically not used as already appended
606 * @param map the <code>Map</code> to add to the <code>toString</code>,
607 * not <code>null</code>
608 */
609 protected void appendDetail(StringBuffer buffer, String fieldName, Map<?, ?> map) {
610 buffer.append(map);
611 }
612
613 /**
614 * <p>Append to the <code>toString</code> an <code>Object</code>
615 * value, printing a summary of the <code>Object</code>.</P>
616 *
617 * @param buffer the <code>StringBuffer</code> to populate
618 * @param fieldName the field name, typically not used as already appended
619 * @param value the value to add to the <code>toString</code>,
620 * not <code>null</code>
621 */
622 protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
623 buffer.append(summaryObjectStartText);
624 buffer.append(getShortClassName(value.getClass()));
625 buffer.append(summaryObjectEndText);
626 }
627
628 //----------------------------------------------------------------------------
629
630 /**
631 * <p>Append to the <code>toString</code> a <code>long</code>
632 * value.</p>
633 *
634 * @param buffer the <code>StringBuffer</code> to populate
635 * @param fieldName the field name
636 * @param value the value to add to the <code>toString</code>
637 */
638 public void append(StringBuffer buffer, String fieldName, long value) {
639 appendFieldStart(buffer, fieldName);
640 appendDetail(buffer, fieldName, value);
641 appendFieldEnd(buffer, fieldName);
642 }
643
644 /**
645 * <p>Append to the <code>toString</code> a <code>long</code>
646 * value.</p>
647 *
648 * @param buffer the <code>StringBuffer</code> to populate
649 * @param fieldName the field name, typically not used as already appended
650 * @param value the value to add to the <code>toString</code>
651 */
652 protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
653 buffer.append(value);
654 }
655
656 //----------------------------------------------------------------------------
657
658 /**
659 * <p>Append to the <code>toString</code> an <code>int</code>
660 * value.</p>
661 *
662 * @param buffer the <code>StringBuffer</code> to populate
663 * @param fieldName the field name
664 * @param value the value to add to the <code>toString</code>
665 */
666 public void append(StringBuffer buffer, String fieldName, int value) {
667 appendFieldStart(buffer, fieldName);
668 appendDetail(buffer, fieldName, value);
669 appendFieldEnd(buffer, fieldName);
670 }
671
672 /**
673 * <p>Append to the <code>toString</code> an <code>int</code>
674 * value.</p>
675 *
676 * @param buffer the <code>StringBuffer</code> to populate
677 * @param fieldName the field name, typically not used as already appended
678 * @param value the value to add to the <code>toString</code>
679 */
680 protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
681 buffer.append(value);
682 }
683
684 //----------------------------------------------------------------------------
685
686 /**
687 * <p>Append to the <code>toString</code> a <code>short</code>
688 * value.</p>
689 *
690 * @param buffer the <code>StringBuffer</code> to populate
691 * @param fieldName the field name
692 * @param value the value to add to the <code>toString</code>
693 */
694 public void append(StringBuffer buffer, String fieldName, short value) {
695 appendFieldStart(buffer, fieldName);
696 appendDetail(buffer, fieldName, value);
697 appendFieldEnd(buffer, fieldName);
698 }
699
700 /**
701 * <p>Append to the <code>toString</code> a <code>short</code>
702 * value.</p>
703 *
704 * @param buffer the <code>StringBuffer</code> to populate
705 * @param fieldName the field name, typically not used as already appended
706 * @param value the value to add to the <code>toString</code>
707 */
708 protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
709 buffer.append(value);
710 }
711
712 //----------------------------------------------------------------------------
713
714 /**
715 * <p>Append to the <code>toString</code> a <code>byte</code>
716 * value.</p>
717 *
718 * @param buffer the <code>StringBuffer</code> to populate
719 * @param fieldName the field name
720 * @param value the value to add to the <code>toString</code>
721 */
722 public void append(StringBuffer buffer, String fieldName, byte value) {
723 appendFieldStart(buffer, fieldName);
724 appendDetail(buffer, fieldName, value);
725 appendFieldEnd(buffer, fieldName);
726 }
727
728 /**
729 * <p>Append to the <code>toString</code> a <code>byte</code>
730 * value.</p>
731 *
732 * @param buffer the <code>StringBuffer</code> to populate
733 * @param fieldName the field name, typically not used as already appended
734 * @param value the value to add to the <code>toString</code>
735 */
736 protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
737 buffer.append(value);
738 }
739
740 //----------------------------------------------------------------------------
741
742 /**
743 * <p>Append to the <code>toString</code> a <code>char</code>
744 * value.</p>
745 *
746 * @param buffer the <code>StringBuffer</code> to populate
747 * @param fieldName the field name
748 * @param value the value to add to the <code>toString</code>
749 */
750 public void append(StringBuffer buffer, String fieldName, char value) {
751 appendFieldStart(buffer, fieldName);
752 appendDetail(buffer, fieldName, value);
753 appendFieldEnd(buffer, fieldName);
754 }
755
756 /**
757 * <p>Append to the <code>toString</code> a <code>char</code>
758 * value.</p>
759 *
760 * @param buffer the <code>StringBuffer</code> to populate
761 * @param fieldName the field name, typically not used as already appended
762 * @param value the value to add to the <code>toString</code>
763 */
764 protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
765 buffer.append(value);
766 }
767
768 //----------------------------------------------------------------------------
769
770 /**
771 * <p>Append to the <code>toString</code> a <code>double</code>
772 * value.</p>
773 *
774 * @param buffer the <code>StringBuffer</code> to populate
775 * @param fieldName the field name
776 * @param value the value to add to the <code>toString</code>
777 */
778 public void append(StringBuffer buffer, String fieldName, double value) {
779 appendFieldStart(buffer, fieldName);
780 appendDetail(buffer, fieldName, value);
781 appendFieldEnd(buffer, fieldName);
782 }
783
784 /**
785 * <p>Append to the <code>toString</code> a <code>double</code>
786 * value.</p>
787 *
788 * @param buffer the <code>StringBuffer</code> to populate
789 * @param fieldName the field name, typically not used as already appended
790 * @param value the value to add to the <code>toString</code>
791 */
792 protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
793 buffer.append(value);
794 }
795
796 //----------------------------------------------------------------------------
797
798 /**
799 * <p>Append to the <code>toString</code> a <code>float</code>
800 * value.</p>
801 *
802 * @param buffer the <code>StringBuffer</code> to populate
803 * @param fieldName the field name
804 * @param value the value to add to the <code>toString</code>
805 */
806 public void append(StringBuffer buffer, String fieldName, float value) {
807 appendFieldStart(buffer, fieldName);
808 appendDetail(buffer, fieldName, value);
809 appendFieldEnd(buffer, fieldName);
810 }
811
812 /**
813 * <p>Append to the <code>toString</code> a <code>float</code>
814 * value.</p>
815 *
816 * @param buffer the <code>StringBuffer</code> to populate
817 * @param fieldName the field name, typically not used as already appended
818 * @param value the value to add to the <code>toString</code>
819 */
820 protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
821 buffer.append(value);
822 }
823
824 //----------------------------------------------------------------------------
825
826 /**
827 * <p>Append to the <code>toString</code> a <code>boolean</code>
828 * value.</p>
829 *
830 * @param buffer the <code>StringBuffer</code> to populate
831 * @param fieldName the field name
832 * @param value the value to add to the <code>toString</code>
833 */
834 public void append(StringBuffer buffer, String fieldName, boolean value) {
835 appendFieldStart(buffer, fieldName);
836 appendDetail(buffer, fieldName, value);
837 appendFieldEnd(buffer, fieldName);
838 }
839
840 /**
841 * <p>Append to the <code>toString</code> a <code>boolean</code>
842 * value.</p>
843 *
844 * @param buffer the <code>StringBuffer</code> to populate
845 * @param fieldName the field name, typically not used as already appended
846 * @param value the value to add to the <code>toString</code>
847 */
848 protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
849 buffer.append(value);
850 }
851
852 /**
853 * <p>Append to the <code>toString</code> an <code>Object</code>
854 * array.</p>
855 *
856 * @param buffer the <code>StringBuffer</code> to populate
857 * @param fieldName the field name
858 * @param array the array to add to the toString
859 * @param fullDetail <code>true</code> for detail, <code>false</code>
860 * for summary info, <code>null</code> for style decides
861 */
862 public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
863 appendFieldStart(buffer, fieldName);
864
865 if (array == null) {
866 appendNullText(buffer, fieldName);
867
868 } else if (isFullDetail(fullDetail)) {
869 appendDetail(buffer, fieldName, array);
870
871 } else {
872 appendSummary(buffer, fieldName, array);
873 }
874
875 appendFieldEnd(buffer, fieldName);
876 }
877
878 //----------------------------------------------------------------------------
879
880 /**
881 * <p>Append to the <code>toString</code> the detail of an
882 * <code>Object</code> array.</p>
883 *
884 * @param buffer the <code>StringBuffer</code> to populate
885 * @param fieldName the field name, typically not used as already appended
886 * @param array the array to add to the <code>toString</code>,
887 * not <code>null</code>
888 */
889 protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
890 buffer.append(arrayStart);
891 for (int i = 0; i < array.length; i++) {
892 Object item = array[i];
893 if (i > 0) {
894 buffer.append(arraySeparator);
895 }
896 if (item == null) {
897 appendNullText(buffer, fieldName);
898
899 } else {
900 appendInternal(buffer, fieldName, item, arrayContentDetail);
901 }
902 }
903 buffer.append(arrayEnd);
904 }
905
906 /**
907 * <p>Append to the <code>toString</code> the detail of an array type.</p>
908 *
909 * @param buffer the <code>StringBuffer</code> to populate
910 * @param fieldName the field name, typically not used as already appended
911 * @param array the array to add to the <code>toString</code>,
912 * not <code>null</code>
913 * @since 2.0
914 */
915 protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
916 buffer.append(arrayStart);
917 int length = Array.getLength(array);
918 for (int i = 0; i < length; i++) {
919 Object item = Array.get(array, i);
920 if (i > 0) {
921 buffer.append(arraySeparator);
922 }
923 if (item == null) {
924 appendNullText(buffer, fieldName);
925
926 } else {
927 appendInternal(buffer, fieldName, item, arrayContentDetail);
928 }
929 }
930 buffer.append(arrayEnd);
931 }
932
933 /**
934 * <p>Append to the <code>toString</code> a summary of an
935 * <code>Object</code> array.</p>
936 *
937 * @param buffer the <code>StringBuffer</code> to populate
938 * @param fieldName the field name, typically not used as already appended
939 * @param array the array to add to the <code>toString</code>,
940 * not <code>null</code>
941 */
942 protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
943 appendSummarySize(buffer, fieldName, array.length);
944 }
945
946 //----------------------------------------------------------------------------
947
948 /**
949 * <p>Append to the <code>toString</code> a <code>long</code>
950 * array.</p>
951 *
952 * @param buffer the <code>StringBuffer</code> to populate
953 * @param fieldName the field name
954 * @param array the array to add to the <code>toString</code>
955 * @param fullDetail <code>true</code> for detail, <code>false</code>
956 * for summary info, <code>null</code> for style decides
957 */
958 public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
959 appendFieldStart(buffer, fieldName);
960
961 if (array == null) {
962 appendNullText(buffer, fieldName);
963
964 } else if (isFullDetail(fullDetail)) {
965 appendDetail(buffer, fieldName, array);
966
967 } else {
968 appendSummary(buffer, fieldName, array);
969 }
970
971 appendFieldEnd(buffer, fieldName);
972 }
973
974 /**
975 * <p>Append to the <code>toString</code> the detail of a
976 * <code>long</code> array.</p>
977 *
978 * @param buffer the <code>StringBuffer</code> to populate
979 * @param fieldName the field name, typically not used as already appended
980 * @param array the array to add to the <code>toString</code>,
981 * not <code>null</code>
982 */
983 protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
984 buffer.append(arrayStart);
985 for (int i = 0; i < array.length; i++) {
986 if (i > 0) {
987 buffer.append(arraySeparator);
988 }
989 appendDetail(buffer, fieldName, array[i]);
990 }
991 buffer.append(arrayEnd);
992 }
993
994 /**
995 * <p>Append to the <code>toString</code> a summary of a
996 * <code>long</code> array.</p>
997 *
998 * @param buffer the <code>StringBuffer</code> to populate
999 * @param fieldName the field name, typically not used as already appended
1000 * @param array the array to add to the <code>toString</code>,
1001 * not <code>null</code>
1002 */
1003 protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
1004 appendSummarySize(buffer, fieldName, array.length);
1005 }
1006
1007 //----------------------------------------------------------------------------
1008
1009 /**
1010 * <p>Append to the <code>toString</code> an <code>int</code>
1011 * array.</p>
1012 *
1013 * @param buffer the <code>StringBuffer</code> to populate
1014 * @param fieldName the field name
1015 * @param array the array to add to the <code>toString</code>
1016 * @param fullDetail <code>true</code> for detail, <code>false</code>
1017 * for summary info, <code>null</code> for style decides
1018 */
1019 public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
1020 appendFieldStart(buffer, fieldName);
1021
1022 if (array == null) {
1023 appendNullText(buffer, fieldName);
1024
1025 } else if (isFullDetail(fullDetail)) {
1026 appendDetail(buffer, fieldName, array);
1027
1028 } else {
1029 appendSummary(buffer, fieldName, array);
1030 }
1031
1032 appendFieldEnd(buffer, fieldName);
1033 }
1034
1035 /**
1036 * <p>Append to the <code>toString</code> the detail of an
1037 * <code>int</code> array.</p>
1038 *
1039 * @param buffer the <code>StringBuffer</code> to populate
1040 * @param fieldName the field name, typically not used as already appended
1041 * @param array the array to add to the <code>toString</code>,
1042 * not <code>null</code>
1043 */
1044 protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
1045 buffer.append(arrayStart);
1046 for (int i = 0; i < array.length; i++) {
1047 if (i > 0) {
1048 buffer.append(arraySeparator);
1049 }
1050 appendDetail(buffer, fieldName, array[i]);
1051 }
1052 buffer.append(arrayEnd);
1053 }
1054
1055 /**
1056 * <p>Append to the <code>toString</code> a summary of an
1057 * <code>int</code> array.</p>
1058 *
1059 * @param buffer the <code>StringBuffer</code> to populate
1060 * @param fieldName the field name, typically not used as already appended
1061 * @param array the array to add to the <code>toString</code>,
1062 * not <code>null</code>
1063 */
1064 protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
1065 appendSummarySize(buffer, fieldName, array.length);
1066 }
1067
1068 //----------------------------------------------------------------------------
1069
1070 /**
1071 * <p>Append to the <code>toString</code> a <code>short</code>
1072 * array.</p>
1073 *
1074 * @param buffer the <code>StringBuffer</code> to populate
1075 * @param fieldName the field name
1076 * @param array the array to add to the <code>toString</code>
1077 * @param fullDetail <code>true</code> for detail, <code>false</code>
1078 * for summary info, <code>null</code> for style decides
1079 */
1080 public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
1081 appendFieldStart(buffer, fieldName);
1082
1083 if (array == null) {
1084 appendNullText(buffer, fieldName);
1085
1086 } else if (isFullDetail(fullDetail)) {
1087 appendDetail(buffer, fieldName, array);
1088
1089 } else {
1090 appendSummary(buffer, fieldName, array);
1091 }
1092
1093 appendFieldEnd(buffer, fieldName);
1094 }
1095
1096 /**
1097 * <p>Append to the <code>toString</code> the detail of a
1098 * <code>short</code> array.</p>
1099 *
1100 * @param buffer the <code>StringBuffer</code> to populate
1101 * @param fieldName the field name, typically not used as already appended
1102 * @param array the array to add to the <code>toString</code>,
1103 * not <code>null</code>
1104 */
1105 protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
1106 buffer.append(arrayStart);
1107 for (int i = 0; i < array.length; i++) {
1108 if (i > 0) {
1109 buffer.append(arraySeparator);
1110 }
1111 appendDetail(buffer, fieldName, array[i]);
1112 }
1113 buffer.append(arrayEnd);
1114 }
1115
1116 /**
1117 * <p>Append to the <code>toString</code> a summary of a
1118 * <code>short</code> array.</p>
1119 *
1120 * @param buffer the <code>StringBuffer</code> to populate
1121 * @param fieldName the field name, typically not used as already appended
1122 * @param array the array to add to the <code>toString</code>,
1123 * not <code>null</code>
1124 */
1125 protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
1126 appendSummarySize(buffer, fieldName, array.length);
1127 }
1128
1129 //----------------------------------------------------------------------------
1130
1131 /**
1132 * <p>Append to the <code>toString</code> a <code>byte</code>
1133 * array.</p>
1134 *
1135 * @param buffer the <code>StringBuffer</code> to populate
1136 * @param fieldName the field name
1137 * @param array the array to add to the <code>toString</code>
1138 * @param fullDetail <code>true</code> for detail, <code>false</code>
1139 * for summary info, <code>null</code> for style decides
1140 */
1141 public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
1142 appendFieldStart(buffer, fieldName);
1143
1144 if (array == null) {
1145 appendNullText(buffer, fieldName);
1146
1147 } else if (isFullDetail(fullDetail)) {
1148 appendDetail(buffer, fieldName, array);
1149
1150 } else {
1151 appendSummary(buffer, fieldName, array);
1152 }
1153
1154 appendFieldEnd(buffer, fieldName);
1155 }
1156
1157 /**
1158 * <p>Append to the <code>toString</code> the detail of a
1159 * <code>byte</code> array.</p>
1160 *
1161 * @param buffer the <code>StringBuffer</code> to populate
1162 * @param fieldName the field name, typically not used as already appended
1163 * @param array the array to add to the <code>toString</code>,
1164 * not <code>null</code>
1165 */
1166 protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
1167 buffer.append(arrayStart);
1168 for (int i = 0; i < array.length; i++) {
1169 if (i > 0) {
1170 buffer.append(arraySeparator);
1171 }
1172 appendDetail(buffer, fieldName, array[i]);
1173 }
1174 buffer.append(arrayEnd);
1175 }
1176
1177 /**
1178 * <p>Append to the <code>toString</code> a summary of a
1179 * <code>byte</code> array.</p>
1180 *
1181 * @param buffer the <code>StringBuffer</code> to populate
1182 * @param fieldName the field name, typically not used as already appended
1183 * @param array the array to add to the <code>toString</code>,
1184 * not <code>null</code>
1185 */
1186 protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
1187 appendSummarySize(buffer, fieldName, array.length);
1188 }
1189
1190 //----------------------------------------------------------------------------
1191
1192 /**
1193 * <p>Append to the <code>toString</code> a <code>char</code>
1194 * array.</p>
1195 *
1196 * @param buffer the <code>StringBuffer</code> to populate
1197 * @param fieldName the field name
1198 * @param array the array to add to the <code>toString</code>
1199 * @param fullDetail <code>true</code> for detail, <code>false</code>
1200 * for summary info, <code>null</code> for style decides
1201 */
1202 public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
1203 appendFieldStart(buffer, fieldName);
1204
1205 if (array == null) {
1206 appendNullText(buffer, fieldName);
1207
1208 } else if (isFullDetail(fullDetail)) {
1209 appendDetail(buffer, fieldName, array);
1210
1211 } else {
1212 appendSummary(buffer, fieldName, array);
1213 }
1214
1215 appendFieldEnd(buffer, fieldName);
1216 }
1217
1218 /**
1219 * <p>Append to the <code>toString</code> the detail of a
1220 * <code>char</code> array.</p>
1221 *
1222 * @param buffer the <code>StringBuffer</code> to populate
1223 * @param fieldName the field name, typically not used as already appended
1224 * @param array the array to add to the <code>toString</code>,
1225 * not <code>null</code>
1226 */
1227 protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
1228 buffer.append(arrayStart);
1229 for (int i = 0; i < array.length; i++) {
1230 if (i > 0) {
1231 buffer.append(arraySeparator);
1232 }
1233 appendDetail(buffer, fieldName, array[i]);
1234 }
1235 buffer.append(arrayEnd);
1236 }
1237
1238 /**
1239 * <p>Append to the <code>toString</code> a summary of a
1240 * <code>char</code> array.</p>
1241 *
1242 * @param buffer the <code>StringBuffer</code> to populate
1243 * @param fieldName the field name, typically not used as already appended
1244 * @param array the array to add to the <code>toString</code>,
1245 * not <code>null</code>
1246 */
1247 protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
1248 appendSummarySize(buffer, fieldName, array.length);
1249 }
1250
1251 //----------------------------------------------------------------------------
1252
1253 /**
1254 * <p>Append to the <code>toString</code> a <code>double</code>
1255 * array.</p>
1256 *
1257 * @param buffer the <code>StringBuffer</code> to populate
1258 * @param fieldName the field name
1259 * @param array the array to add to the toString
1260 * @param fullDetail <code>true</code> for detail, <code>false</code>
1261 * for summary info, <code>null</code> for style decides
1262 */
1263 public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
1264 appendFieldStart(buffer, fieldName);
1265
1266 if (array == null) {
1267 appendNullText(buffer, fieldName);
1268
1269 } else if (isFullDetail(fullDetail)) {
1270 appendDetail(buffer, fieldName, array);
1271
1272 } else {
1273 appendSummary(buffer, fieldName, array);
1274 }
1275
1276 appendFieldEnd(buffer, fieldName);
1277 }
1278
1279 /**
1280 * <p>Append to the <code>toString</code> the detail of a
1281 * <code>double</code> array.</p>
1282 *
1283 * @param buffer the <code>StringBuffer</code> to populate
1284 * @param fieldName the field name, typically not used as already appended
1285 * @param array the array to add to the <code>toString</code>,
1286 * not <code>null</code>
1287 */
1288 protected void appendDetail(StringBuffer buffer, String fieldName, double[] array) {
1289 buffer.append(arrayStart);
1290 for (int i = 0; i < array.length; i++) {
1291 if (i > 0) {
1292 buffer.append(arraySeparator);
1293 }
1294 appendDetail(buffer, fieldName, array[i]);
1295 }
1296 buffer.append(arrayEnd);
1297 }
1298
1299 /**
1300 * <p>Append to the <code>toString</code> a summary of a
1301 * <code>double</code> array.</p>
1302 *
1303 * @param buffer the <code>StringBuffer</code> to populate
1304 * @param fieldName the field name, typically not used as already appended
1305 * @param array the array to add to the <code>toString</code>,
1306 * not <code>null</code>
1307 */
1308 protected void appendSummary(StringBuffer buffer, String fieldName, double[] array) {
1309 appendSummarySize(buffer, fieldName, array.length);
1310 }
1311
1312 //----------------------------------------------------------------------------
1313
1314 /**
1315 * <p>Append to the <code>toString</code> a <code>float</code>
1316 * array.</p>
1317 *
1318 * @param buffer the <code>StringBuffer</code> to populate
1319 * @param fieldName the field name
1320 * @param array the array to add to the toString
1321 * @param fullDetail <code>true</code> for detail, <code>false</code>
1322 * for summary info, <code>null</code> for style decides
1323 */
1324 public void append(StringBuffer buffer, String fieldName, float[] array, Boolean fullDetail) {
1325 appendFieldStart(buffer, fieldName);
1326
1327 if (array == null) {
1328 appendNullText(buffer, fieldName);
1329
1330 } else if (isFullDetail(fullDetail)) {
1331 appendDetail(buffer, fieldName, array);
1332
1333 } else {
1334 appendSummary(buffer, fieldName, array);
1335 }
1336
1337 appendFieldEnd(buffer, fieldName);
1338 }
1339
1340 /**
1341 * <p>Append to the <code>toString</code> the detail of a
1342 * <code>float</code> array.</p>
1343 *
1344 * @param buffer the <code>StringBuffer</code> to populate
1345 * @param fieldName the field name, typically not used as already appended
1346 * @param array the array to add to the <code>toString</code>,
1347 * not <code>null</code>
1348 */
1349 protected void appendDetail(StringBuffer buffer, String fieldName, float[] array) {
1350 buffer.append(arrayStart);
1351 for (int i = 0; i < array.length; i++) {
1352 if (i > 0) {
1353 buffer.append(arraySeparator);
1354 }
1355 appendDetail(buffer, fieldName, array[i]);
1356 }
1357 buffer.append(arrayEnd);
1358 }
1359
1360 /**
1361 * <p>Append to the <code>toString</code> a summary of a
1362 * <code>float</code> array.</p>
1363 *
1364 * @param buffer the <code>StringBuffer</code> to populate
1365 * @param fieldName the field name, typically not used as already appended
1366 * @param array the array to add to the <code>toString</code>,
1367 * not <code>null</code>
1368 */
1369 protected void appendSummary(StringBuffer buffer, String fieldName, float[] array) {
1370 appendSummarySize(buffer, fieldName, array.length);
1371 }
1372
1373 //----------------------------------------------------------------------------
1374
1375 /**
1376 * <p>Append to the <code>toString</code> a <code>boolean</code>
1377 * array.</p>
1378 *
1379 * @param buffer the <code>StringBuffer</code> to populate
1380 * @param fieldName the field name
1381 * @param array the array to add to the toString
1382 * @param fullDetail <code>true</code> for detail, <code>false</code>
1383 * for summary info, <code>null</code> for style decides
1384 */
1385 public void append(StringBuffer buffer, String fieldName, boolean[] array, Boolean fullDetail) {
1386 appendFieldStart(buffer, fieldName);
1387
1388 if (array == null) {
1389 appendNullText(buffer, fieldName);
1390
1391 } else if (isFullDetail(fullDetail)) {
1392 appendDetail(buffer, fieldName, array);
1393
1394 } else {
1395 appendSummary(buffer, fieldName, array);
1396 }
1397
1398 appendFieldEnd(buffer, fieldName);
1399 }
1400
1401 /**
1402 * <p>Append to the <code>toString</code> the detail of a
1403 * <code>boolean</code> array.</p>
1404 *
1405 * @param buffer the <code>StringBuffer</code> to populate
1406 * @param fieldName the field name, typically not used as already appended
1407 * @param array the array to add to the <code>toString</code>,
1408 * not <code>null</code>
1409 */
1410 protected void appendDetail(StringBuffer buffer, String fieldName, boolean[] array) {
1411 buffer.append(arrayStart);
1412 for (int i = 0; i < array.length; i++) {
1413 if (i > 0) {
1414 buffer.append(arraySeparator);
1415 }
1416 appendDetail(buffer, fieldName, array[i]);
1417 }
1418 buffer.append(arrayEnd);
1419 }
1420
1421 /**
1422 * <p>Append to the <code>toString</code> a summary of a
1423 * <code>boolean</code> array.</p>
1424 *
1425 * @param buffer the <code>StringBuffer</code> to populate
1426 * @param fieldName the field name, typically not used as already appended
1427 * @param array the array to add to the <code>toString</code>,
1428 * not <code>null</code>
1429 */
1430 protected void appendSummary(StringBuffer buffer, String fieldName, boolean[] array) {
1431 appendSummarySize(buffer, fieldName, array.length);
1432 }
1433
1434 //----------------------------------------------------------------------------
1435
1436 /**
1437 * <p>Append to the <code>toString</code> the class name.</p>
1438 *
1439 * @param buffer the <code>StringBuffer</code> to populate
1440 * @param object the <code>Object</code> whose name to output
1441 */
1442 protected void appendClassName(StringBuffer buffer, Object object) {
1443 if (useClassName && object != null) {
1444 register(object);
1445 if (useShortClassName) {
1446 buffer.append(getShortClassName(object.getClass()));
1447 } else {
1448 buffer.append(object.getClass().getName());
1449 }
1450 }
1451 }
1452
1453 /**
1454 * <p>Append the {@link System#identityHashCode(java.lang.Object)}.</p>
1455 *
1456 * @param buffer the <code>StringBuffer</code> to populate
1457 * @param object the <code>Object</code> whose id to output
1458 */
1459 protected void appendIdentityHashCode(StringBuffer buffer, Object object) {
1460 if (this.isUseIdentityHashCode() && object!=null) {
1461 register(object);
1462 buffer.append('@');
1463 buffer.append(Integer.toHexString(System.identityHashCode(object)));
1464 }
1465 }
1466
1467 /**
1468 * <p>Append to the <code>toString</code> the content start.</p>
1469 *
1470 * @param buffer the <code>StringBuffer</code> to populate
1471 */
1472 protected void appendContentStart(StringBuffer buffer) {
1473 buffer.append(contentStart);
1474 }
1475
1476 /**
1477 * <p>Append to the <code>toString</code> the content end.</p>
1478 *
1479 * @param buffer the <code>StringBuffer</code> to populate
1480 */
1481 protected void appendContentEnd(StringBuffer buffer) {
1482 buffer.append(contentEnd);
1483 }
1484
1485 /**
1486 * <p>Append to the <code>toString</code> an indicator for <code>null</code>.</p>
1487 *
1488 * <p>The default indicator is <code>'<null>'</code>.</p>
1489 *
1490 * @param buffer the <code>StringBuffer</code> to populate
1491 * @param fieldName the field name, typically not used as already appended
1492 */
1493 protected void appendNullText(StringBuffer buffer, String fieldName) {
1494 buffer.append(nullText);
1495 }
1496
1497 /**
1498 * <p>Append to the <code>toString</code> the field separator.</p>
1499 *
1500 * @param buffer the <code>StringBuffer</code> to populate
1501 */
1502 protected void appendFieldSeparator(StringBuffer buffer) {
1503 buffer.append(fieldSeparator);
1504 }
1505
1506 /**
1507 * <p>Append to the <code>toString</code> the field start.</p>
1508 *
1509 * @param buffer the <code>StringBuffer</code> to populate
1510 * @param fieldName the field name
1511 */
1512 protected void appendFieldStart(StringBuffer buffer, String fieldName) {
1513 if (useFieldNames && fieldName != null) {
1514 buffer.append(fieldName);
1515 buffer.append(fieldNameValueSeparator);
1516 }
1517 }
1518
1519 /**
1520 * <p>Append to the <code>toString<code> the field end.</p>
1521 *
1522 * @param buffer the <code>StringBuffer</code> to populate
1523 * @param fieldName the field name, typically not used as already appended
1524 */
1525 protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
1526 appendFieldSeparator(buffer);
1527 }
1528
1529 /**
1530 * <p>Append to the <code>toString</code> a size summary.</p>
1531 *
1532 * <p>The size summary is used to summarize the contents of
1533 * <code>Collections</code>, <code>Maps</code> and arrays.</p>
1534 *
1535 * <p>The output consists of a prefix, the passed in size
1536 * and a suffix.</p>
1537 *
1538 * <p>The default format is <code>'<size=n>'<code>.</p>
1539 *
1540 * @param buffer the <code>StringBuffer</code> to populate
1541 * @param fieldName the field name, typically not used as already appended
1542 * @param size the size to append
1543 */
1544 protected void appendSummarySize(StringBuffer buffer, String fieldName, int size) {
1545 buffer.append(sizeStartText);
1546 buffer.append(size);
1547 buffer.append(sizeEndText);
1548 }
1549
1550 /**
1551 * <p>Is this field to be output in full detail.</p>
1552 *
1553 * <p>This method converts a detail request into a detail level.
1554 * The calling code may request full detail (<code>true</code>),
1555 * but a subclass might ignore that and always return
1556 * <code>false</code>. The calling code may pass in
1557 * <code>null</code> indicating that it doesn't care about
1558 * the detail level. In this case the default detail level is
1559 * used.</p>
1560 *
1561 * @param fullDetailRequest the detail level requested
1562 * @return whether full detail is to be shown
1563 */
1564 protected boolean isFullDetail(Boolean fullDetailRequest) {
1565 if (fullDetailRequest == null) {
1566 return defaultFullDetail;
1567 }
1568 return fullDetailRequest.booleanValue();
1569 }
1570
1571 /**
1572 * <p>Gets the short class name for a class.</p>
1573 *
1574 * <p>The short class name is the classname excluding
1575 * the package name.</p>
1576 *
1577 * @param cls the <code>Class</code> to get the short name of
1578 * @return the short name
1579 */
1580 protected String getShortClassName(Class<?> cls) {
1581 return ClassUtils.getShortClassName(cls);
1582 }
1583
1584 // Setters and getters for the customizable parts of the style
1585 // These methods are not expected to be overridden, except to make public
1586 // (They are not public so that immutable subclasses can be written)
1587 //---------------------------------------------------------------------
1588
1589 /**
1590 * <p>Gets whether to use the class name.</p>
1591 *
1592 * @return the current useClassName flag
1593 */
1594 protected boolean isUseClassName() {
1595 return useClassName;
1596 }
1597
1598 /**
1599 * <p>Sets whether to use the class name.</p>
1600 *
1601 * @param useClassName the new useClassName flag
1602 */
1603 protected void setUseClassName(boolean useClassName) {
1604 this.useClassName = useClassName;
1605 }
1606
1607 //---------------------------------------------------------------------
1608
1609 /**
1610 * <p>Gets whether to output short or long class names.</p>
1611 *
1612 * @return the current useShortClassName flag
1613 * @since 2.0
1614 */
1615 protected boolean isUseShortClassName() {
1616 return useShortClassName;
1617 }
1618
1619 /**
1620 * <p>Sets whether to output short or long class names.</p>
1621 *
1622 * @param useShortClassName the new useShortClassName flag
1623 * @since 2.0
1624 */
1625 protected void setUseShortClassName(boolean useShortClassName) {
1626 this.useShortClassName = useShortClassName;
1627 }
1628
1629 //---------------------------------------------------------------------
1630
1631 /**
1632 * <p>Gets whether to use the identity hash code.</p>
1633 *
1634 * @return the current useIdentityHashCode flag
1635 */
1636 protected boolean isUseIdentityHashCode() {
1637 return useIdentityHashCode;
1638 }
1639
1640 /**
1641 * <p>Sets whether to use the identity hash code.</p>
1642 *
1643 * @param useIdentityHashCode the new useIdentityHashCode flag
1644 */
1645 protected void setUseIdentityHashCode(boolean useIdentityHashCode) {
1646 this.useIdentityHashCode = useIdentityHashCode;
1647 }
1648
1649 //---------------------------------------------------------------------
1650
1651 /**
1652 * <p>Gets whether to use the field names passed in.</p>
1653 *
1654 * @return the current useFieldNames flag
1655 */
1656 protected boolean isUseFieldNames() {
1657 return useFieldNames;
1658 }
1659
1660 /**
1661 * <p>Sets whether to use the field names passed in.</p>
1662 *
1663 * @param useFieldNames the new useFieldNames flag
1664 */
1665 protected void setUseFieldNames(boolean useFieldNames) {
1666 this.useFieldNames = useFieldNames;
1667 }
1668
1669 //---------------------------------------------------------------------
1670
1671 /**
1672 * <p>Gets whether to use full detail when the caller doesn't
1673 * specify.</p>
1674 *
1675 * @return the current defaultFullDetail flag
1676 */
1677 protected boolean isDefaultFullDetail() {
1678 return defaultFullDetail;
1679 }
1680
1681 /**
1682 * <p>Sets whether to use full detail when the caller doesn't
1683 * specify.</p>
1684 *
1685 * @param defaultFullDetail the new defaultFullDetail flag
1686 */
1687 protected void setDefaultFullDetail(boolean defaultFullDetail) {
1688 this.defaultFullDetail = defaultFullDetail;
1689 }
1690
1691 //---------------------------------------------------------------------
1692
1693 /**
1694 * <p>Gets whether to output array content detail.</p>
1695 *
1696 * @return the current array content detail setting
1697 */
1698 protected boolean isArrayContentDetail() {
1699 return arrayContentDetail;
1700 }
1701
1702 /**
1703 * <p>Sets whether to output array content detail.</p>
1704 *
1705 * @param arrayContentDetail the new arrayContentDetail flag
1706 */
1707 protected void setArrayContentDetail(boolean arrayContentDetail) {
1708 this.arrayContentDetail = arrayContentDetail;
1709 }
1710
1711 //---------------------------------------------------------------------
1712
1713 /**
1714 * <p>Gets the array start text.</p>
1715 *
1716 * @return the current array start text
1717 */
1718 protected String getArrayStart() {
1719 return arrayStart;
1720 }
1721
1722 /**
1723 * <p>Sets the array start text.</p>
1724 *
1725 * <p><code>null</code> is accepted, but will be converted to
1726 * an empty String.</p>
1727 *
1728 * @param arrayStart the new array start text
1729 */
1730 protected void setArrayStart(String arrayStart) {
1731 if (arrayStart == null) {
1732 arrayStart = "";
1733 }
1734 this.arrayStart = arrayStart;
1735 }
1736
1737 //---------------------------------------------------------------------
1738
1739 /**
1740 * <p>Gets the array end text.</p>
1741 *
1742 * @return the current array end text
1743 */
1744 protected String getArrayEnd() {
1745 return arrayEnd;
1746 }
1747
1748 /**
1749 * <p>Sets the array end text.</p>
1750 *
1751 * <p><code>null</code> is accepted, but will be converted to
1752 * an empty String.</p>
1753 *
1754 * @param arrayEnd the new array end text
1755 */
1756 protected void setArrayEnd(String arrayEnd) {
1757 if (arrayEnd == null) {
1758 arrayEnd = "";
1759 }
1760 this.arrayEnd = arrayEnd;
1761 }
1762
1763 //---------------------------------------------------------------------
1764
1765 /**
1766 * <p>Gets the array separator text.</p>
1767 *
1768 * @return the current array separator text
1769 */
1770 protected String getArraySeparator() {
1771 return arraySeparator;
1772 }
1773
1774 /**
1775 * <p>Sets the array separator text.</p>
1776 *
1777 * <p><code>null</code> is accepted, but will be converted to
1778 * an empty String.</p>
1779 *
1780 * @param arraySeparator the new array separator text
1781 */
1782 protected void setArraySeparator(String arraySeparator) {
1783 if (arraySeparator == null) {
1784 arraySeparator = "";
1785 }
1786 this.arraySeparator = arraySeparator;
1787 }
1788
1789 //---------------------------------------------------------------------
1790
1791 /**
1792 * <p>Gets the content start text.</p>
1793 *
1794 * @return the current content start text
1795 */
1796 protected String getContentStart() {
1797 return contentStart;
1798 }
1799
1800 /**
1801 * <p>Sets the content start text.</p>
1802 *
1803 * <p><code>null</code> is accepted, but will be converted to
1804 * an empty String.</p>
1805 *
1806 * @param contentStart the new content start text
1807 */
1808 protected void setContentStart(String contentStart) {
1809 if (contentStart == null) {
1810 contentStart = "";
1811 }
1812 this.contentStart = contentStart;
1813 }
1814
1815 //---------------------------------------------------------------------
1816
1817 /**
1818 * <p>Gets the content end text.</p>
1819 *
1820 * @return the current content end text
1821 */
1822 protected String getContentEnd() {
1823 return contentEnd;
1824 }
1825
1826 /**
1827 * <p>Sets the content end text.</p>
1828 *
1829 * <p><code>null</code> is accepted, but will be converted to
1830 * an empty String.</p>
1831 *
1832 * @param contentEnd the new content end text
1833 */
1834 protected void setContentEnd(String contentEnd) {
1835 if (contentEnd == null) {
1836 contentEnd = "";
1837 }
1838 this.contentEnd = contentEnd;
1839 }
1840
1841 //---------------------------------------------------------------------
1842
1843 /**
1844 * <p>Gets the field name value separator text.</p>
1845 *
1846 * @return the current field name value separator text
1847 */
1848 protected String getFieldNameValueSeparator() {
1849 return fieldNameValueSeparator;
1850 }
1851
1852 /**
1853 * <p>Sets the field name value separator text.</p>
1854 *
1855 * <p><code>null</code> is accepted, but will be converted to
1856 * an empty String.</p>
1857 *
1858 * @param fieldNameValueSeparator the new field name value separator text
1859 */
1860 protected void setFieldNameValueSeparator(String fieldNameValueSeparator) {
1861 if (fieldNameValueSeparator == null) {
1862 fieldNameValueSeparator = "";
1863 }
1864 this.fieldNameValueSeparator = fieldNameValueSeparator;
1865 }
1866
1867 //---------------------------------------------------------------------
1868
1869 /**
1870 * <p>Gets the field separator text.</p>
1871 *
1872 * @return the current field separator text
1873 */
1874 protected String getFieldSeparator() {
1875 return fieldSeparator;
1876 }
1877
1878 /**
1879 * <p>Sets the field separator text.</p>
1880 *
1881 * <p><code>null</code> is accepted, but will be converted to
1882 * an empty String.</p>
1883 *
1884 * @param fieldSeparator the new field separator text
1885 */
1886 protected void setFieldSeparator(String fieldSeparator) {
1887 if (fieldSeparator == null) {
1888 fieldSeparator = "";
1889 }
1890 this.fieldSeparator = fieldSeparator;
1891 }
1892
1893 //---------------------------------------------------------------------
1894
1895 /**
1896 * <p>Gets whether the field separator should be added at the start
1897 * of each buffer.</p>
1898 *
1899 * @return the fieldSeparatorAtStart flag
1900 * @since 2.0
1901 */
1902 protected boolean isFieldSeparatorAtStart() {
1903 return fieldSeparatorAtStart;
1904 }
1905
1906 /**
1907 * <p>Sets whether the field separator should be added at the start
1908 * of each buffer.</p>
1909 *
1910 * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag
1911 * @since 2.0
1912 */
1913 protected void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) {
1914 this.fieldSeparatorAtStart = fieldSeparatorAtStart;
1915 }
1916
1917 //---------------------------------------------------------------------
1918
1919 /**
1920 * <p>Gets whether the field separator should be added at the end
1921 * of each buffer.</p>
1922 *
1923 * @return fieldSeparatorAtEnd flag
1924 * @since 2.0
1925 */
1926 protected boolean isFieldSeparatorAtEnd() {
1927 return fieldSeparatorAtEnd;
1928 }
1929
1930 /**
1931 * <p>Sets whether the field separator should be added at the end
1932 * of each buffer.</p>
1933 *
1934 * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag
1935 * @since 2.0
1936 */
1937 protected void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) {
1938 this.fieldSeparatorAtEnd = fieldSeparatorAtEnd;
1939 }
1940
1941 //---------------------------------------------------------------------
1942
1943 /**
1944 * <p>Gets the text to output when <code>null</code> found.</p>
1945 *
1946 * @return the current text to output when null found
1947 */
1948 protected String getNullText() {
1949 return nullText;
1950 }
1951
1952 /**
1953 * <p>Sets the text to output when <code>null</code> found.</p>
1954 *
1955 * <p><code>null</code> is accepted, but will be converted to
1956 * an empty String.</p>
1957 *
1958 * @param nullText the new text to output when null found
1959 */
1960 protected void setNullText(String nullText) {
1961 if (nullText == null) {
1962 nullText = "";
1963 }
1964 this.nullText = nullText;
1965 }
1966
1967 //---------------------------------------------------------------------
1968
1969 /**
1970 * <p>Gets the start text to output when a <code>Collection</code>,
1971 * <code>Map</code> or array size is output.</p>
1972 *
1973 * <p>This is output before the size value.</p>
1974 *
1975 * @return the current start of size text
1976 */
1977 protected String getSizeStartText() {
1978 return sizeStartText;
1979 }
1980
1981 /**
1982 * <p>Sets the start text to output when a <code>Collection</code>,
1983 * <code>Map</code> or array size is output.</p>
1984 *
1985 * <p>This is output before the size value.</p>
1986 *
1987 * <p><code>null</code> is accepted, but will be converted to
1988 * an empty String.</p>
1989 *
1990 * @param sizeStartText the new start of size text
1991 */
1992 protected void setSizeStartText(String sizeStartText) {
1993 if (sizeStartText == null) {
1994 sizeStartText = "";
1995 }
1996 this.sizeStartText = sizeStartText;
1997 }
1998
1999 //---------------------------------------------------------------------
2000
2001 /**
2002 * <p>Gets the end text to output when a <code>Collection</code>,
2003 * <code>Map</code> or array size is output.</p>
2004 *
2005 * <p>This is output after the size value.</p>
2006 *
2007 * @return the current end of size text
2008 */
2009 protected String getSizeEndText() {
2010 return sizeEndText;
2011 }
2012
2013 /**
2014 * <p>Sets the end text to output when a <code>Collection</code>,
2015 * <code>Map</code> or array size is output.</p>
2016 *
2017 * <p>This is output after the size value.</p>
2018 *
2019 * <p><code>null</code> is accepted, but will be converted to
2020 * an empty String.</p>
2021 *
2022 * @param sizeEndText the new end of size text
2023 */
2024 protected void setSizeEndText(String sizeEndText) {
2025 if (sizeEndText == null) {
2026 sizeEndText = "";
2027 }
2028 this.sizeEndText = sizeEndText;
2029 }
2030
2031 //---------------------------------------------------------------------
2032
2033 /**
2034 * <p>Gets the start text to output when an <code>Object</code> is
2035 * output in summary mode.</p>
2036 *
2037 * <p>This is output before the size value.</p>
2038 *
2039 * @return the current start of summary text
2040 */
2041 protected String getSummaryObjectStartText() {
2042 return summaryObjectStartText;
2043 }
2044
2045 /**
2046 * <p>Sets the start text to output when an <code>Object</code> is
2047 * output in summary mode.</p>
2048 *
2049 * <p>This is output before the size value.</p>
2050 *
2051 * <p><code>null</code> is accepted, but will be converted to
2052 * an empty String.</p>
2053 *
2054 * @param summaryObjectStartText the new start of summary text
2055 */
2056 protected void setSummaryObjectStartText(String summaryObjectStartText) {
2057 if (summaryObjectStartText == null) {
2058 summaryObjectStartText = "";
2059 }
2060 this.summaryObjectStartText = summaryObjectStartText;
2061 }
2062
2063 //---------------------------------------------------------------------
2064
2065 /**
2066 * <p>Gets the end text to output when an <code>Object</code> is
2067 * output in summary mode.</p>
2068 *
2069 * <p>This is output after the size value.</p>
2070 *
2071 * @return the current end of summary text
2072 */
2073 protected String getSummaryObjectEndText() {
2074 return summaryObjectEndText;
2075 }
2076
2077 /**
2078 * <p>Sets the end text to output when an <code>Object</code> is
2079 * output in summary mode.</p>
2080 *
2081 * <p>This is output after the size value.</p>
2082 *
2083 * <p><code>null</code> is accepted, but will be converted to
2084 * an empty String.</p>
2085 *
2086 * @param summaryObjectEndText the new end of summary text
2087 */
2088 protected void setSummaryObjectEndText(String summaryObjectEndText) {
2089 if (summaryObjectEndText == null) {
2090 summaryObjectEndText = "";
2091 }
2092 this.summaryObjectEndText = summaryObjectEndText;
2093 }
2094
2095 //----------------------------------------------------------------------------
2096
2097 /**
2098 * <p>Default <code>ToStringStyle</code>.</p>
2099 *
2100 * <p>This is an inner class rather than using
2101 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2102 */
2103 private static final class DefaultToStringStyle extends ToStringStyle {
2104
2105 /**
2106 * Required for serialization support.
2107 *
2108 * @see java.io.Serializable
2109 */
2110 private static final long serialVersionUID = 1L;
2111
2112 /**
2113 * <p>Constructor.</p>
2114 *
2115 * <p>Use the static constant rather than instantiating.</p>
2116 */
2117 DefaultToStringStyle() {
2118 super();
2119 }
2120
2121 /**
2122 * <p>Ensure <code>Singleton</code> after serialization.</p>
2123 *
2124 * @return the singleton
2125 */
2126 private Object readResolve() {
2127 return ToStringStyle.DEFAULT_STYLE;
2128 }
2129
2130 }
2131
2132 //----------------------------------------------------------------------------
2133
2134 /**
2135 * <p><code>ToStringStyle</code> that does not print out
2136 * the field names.</p>
2137 *
2138 * <p>This is an inner class rather than using
2139 * <code>StandardToStringStyle</code> to ensure its immutability.
2140 */
2141 private static final class NoFieldNameToStringStyle extends ToStringStyle {
2142
2143 private static final long serialVersionUID = 1L;
2144
2145 /**
2146 * <p>Constructor.</p>
2147 *
2148 * <p>Use the static constant rather than instantiating.</p>
2149 */
2150 NoFieldNameToStringStyle() {
2151 super();
2152 this.setUseFieldNames(false);
2153 }
2154
2155 /**
2156 * <p>Ensure <code>Singleton</code> after serialization.</p>
2157 *
2158 * @return the singleton
2159 */
2160 private Object readResolve() {
2161 return ToStringStyle.NO_FIELD_NAMES_STYLE;
2162 }
2163
2164 }
2165
2166 //----------------------------------------------------------------------------
2167
2168 /**
2169 * <p><code>ToStringStyle</code> that prints out the short
2170 * class name and no identity hashcode.</p>
2171 *
2172 * <p>This is an inner class rather than using
2173 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2174 */
2175 private static final class ShortPrefixToStringStyle extends ToStringStyle {
2176
2177 private static final long serialVersionUID = 1L;
2178
2179 /**
2180 * <p>Constructor.</p>
2181 *
2182 * <p>Use the static constant rather than instantiating.</p>
2183 */
2184 ShortPrefixToStringStyle() {
2185 super();
2186 this.setUseShortClassName(true);
2187 this.setUseIdentityHashCode(false);
2188 }
2189
2190 /**
2191 * <p>Ensure <code>Singleton</ode> after serialization.</p>
2192 * @return the singleton
2193 */
2194 private Object readResolve() {
2195 return ToStringStyle.SHORT_PREFIX_STYLE;
2196 }
2197
2198 }
2199
2200 /**
2201 * <p><code>ToStringStyle</code> that does not print out the
2202 * classname, identity hashcode, content start or field name.</p>
2203 *
2204 * <p>This is an inner class rather than using
2205 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2206 */
2207 private static final class SimpleToStringStyle extends ToStringStyle {
2208
2209 private static final long serialVersionUID = 1L;
2210
2211 /**
2212 * <p>Constructor.</p>
2213 *
2214 * <p>Use the static constant rather than instantiating.</p>
2215 */
2216 SimpleToStringStyle() {
2217 super();
2218 this.setUseClassName(false);
2219 this.setUseIdentityHashCode(false);
2220 this.setUseFieldNames(false);
2221 this.setContentStart("");
2222 this.setContentEnd("");
2223 }
2224
2225 /**
2226 * <p>Ensure <code>Singleton</ode> after serialization.</p>
2227 * @return the singleton
2228 */
2229 private Object readResolve() {
2230 return ToStringStyle.SIMPLE_STYLE;
2231 }
2232
2233 }
2234
2235 //----------------------------------------------------------------------------
2236
2237 /**
2238 * <p><code>ToStringStyle</code> that outputs on multiple lines.</p>
2239 *
2240 * <p>This is an inner class rather than using
2241 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2242 */
2243 private static final class MultiLineToStringStyle extends ToStringStyle {
2244
2245 private static final long serialVersionUID = 1L;
2246
2247 /**
2248 * <p>Constructor.</p>
2249 *
2250 * <p>Use the static constant rather than instantiating.</p>
2251 */
2252 MultiLineToStringStyle() {
2253 super();
2254 this.setContentStart("[");
2255 this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + " ");
2256 this.setFieldSeparatorAtStart(true);
2257 this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]");
2258 }
2259
2260 /**
2261 * <p>Ensure <code>Singleton</code> after serialization.</p>
2262 *
2263 * @return the singleton
2264 */
2265 private Object readResolve() {
2266 return ToStringStyle.MULTI_LINE_STYLE;
2267 }
2268
2269 }
2270
2271 }