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